Skip to content

Commit a83e1d9

Browse files
authored
feat: accept any audio input (any rate/channels, wav/mp3/flac) via miniaudio (#2994)
* feat(runtime): accept any audio (any sample-rate/channels, wav/mp3/flac) via miniaudio Replaces the 16k-mono-PCM16-only WAV reader with a miniaudio-based loader (funasr-common/funasr_audio.h) that decodes wav/mp3/flac at any sample rate and channel count, resampling to 16 kHz mono. Verified: a 44.1k stereo file and an 8k mono file both transcribe correctly across cli/sensevoice/paraformer. * fix(audio): inline loader (avoid duplicate symbols), null-path guard, check decoder read result (gemini review) --------- Co-authored-by: LauraGPT <LauraGPT@users.noreply.github.com>
1 parent 842e62f commit a83e1d9

8 files changed

Lines changed: 95928 additions & 50 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
set(TARGET llama-funasr-cli)
22
add_executable(${TARGET} funasr-cli.cpp)
33
install(TARGETS ${TARGET} RUNTIME)
4+
target_include_directories(${TARGET} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../funasr-common)
45
target_link_libraries(${TARGET} PRIVATE llama ggml ${CMAKE_THREAD_LIBS_INIT})
56
target_compile_features(${TARGET} PRIVATE cxx_std_17)

runtime/llama.cpp/fun-asr-nano/funasr-cli/funasr-cli.cpp

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,9 @@
2323
#include <string>
2424
#include <vector>
2525

26-
// ======================= WAV (16 kHz mono PCM16) =======================
27-
static bool read_wav16(const char * path, std::vector<float> & out) {
28-
FILE * f = fopen(path, "rb"); if (!f) return false;
29-
char riff[4]; fread(riff, 1, 4, f);
30-
if (strncmp(riff, "RIFF", 4)) { fclose(f); return false; }
31-
fseek(f, 4, SEEK_CUR); char wave[4]; fread(wave, 1, 4, f);
32-
if (strncmp(wave, "WAVE", 4)) { fclose(f); return false; }
33-
uint16_t ch = 1, bits = 16; uint32_t sr = 16000;
34-
while (!feof(f)) {
35-
char id[4]; if (fread(id, 1, 4, f) != 4) break;
36-
uint32_t sz; if (fread(&sz, 4, 1, f) != 1) break;
37-
if (!strncmp(id, "fmt ", 4)) {
38-
uint16_t fmt; fread(&fmt, 2, 1, f); fread(&ch, 2, 1, f);
39-
fread(&sr, 4, 1, f); fseek(f, 6, SEEK_CUR); fread(&bits, 2, 1, f);
40-
if (sz > 16) fseek(f, sz - 16, SEEK_CUR);
41-
} else if (!strncmp(id, "data", 4)) {
42-
if (ch < 1 || bits != 16) { fclose(f); fprintf(stderr, "only 16-bit PCM WAV supported (ch=%u bits=%u)\n", ch, bits); return false; }
43-
int n = sz / (bits / 8);
44-
std::vector<int16_t> pcm(n); fread(pcm.data(), 2, n, f);
45-
out.resize(n / ch);
46-
for (int i = 0; i < n / ch; i++) out[i] = pcm[i * ch] / 32768.0f; // ch0
47-
fclose(f);
48-
if (sr != 16000) fprintf(stderr, "warning: sample rate %u != 16000\n", sr);
49-
return true;
50-
} else fseek(f, sz, SEEK_CUR);
51-
}
52-
fclose(f); return false;
53-
}
26+
// any audio (wav/mp3/flac, any rate/channels) -> 16 kHz mono f32, via miniaudio
27+
#define FUNASR_AUDIO_IMPLEMENTATION
28+
#include "funasr_audio.h"
5429

5530
// ======================= kaldi fbank + LFR =======================
5631
static const int FS=16000, WINLEN=400, SHIFT=160, NFFT=512, NMEL=80, LFR_M=7, LFR_N=6;
@@ -202,7 +177,7 @@ int main(int argc,char**argv){
202177
if(enc_path.empty()||llm_path.empty()||wav_path.empty()){fprintf(stderr,"missing args\n");return 1;}
203178

204179
std::vector<float> wav;
205-
if(!read_wav16(wav_path.c_str(),wav)){fprintf(stderr,"failed to read wav\n");return 1;}
180+
if(!funasr_load_audio_16k_mono(wav_path.c_str(),wav)){fprintf(stderr,"failed to read audio\n");return 1;}
206181
int64_t t0=ggml_time_us();
207182

208183
enc_model em; if(!load_enc(enc_path.c_str(),em))return 1;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// funasr_audio.h — load any audio file (WAV/MP3/FLAC/OGG...) as 16 kHz mono f32,
2+
// via miniaudio's decoder (handles arbitrary sample rate, channels, bit depth).
3+
// One TU must define FUNASR_AUDIO_IMPLEMENTATION before including.
4+
#ifndef FUNASR_AUDIO_H
5+
#define FUNASR_AUDIO_H
6+
#include <vector>
7+
// returns true on success; out = mono 16 kHz float samples in [-1,1]
8+
inline bool funasr_load_audio_16k_mono(const char * path, std::vector<float> & out);
9+
#endif
10+
11+
#ifdef FUNASR_AUDIO_IMPLEMENTATION
12+
// keep only the decoder + data conversion (resampler/channel mixer); drop playback/capture
13+
#define MA_NO_DEVICE_IO
14+
#define MA_NO_ENGINE
15+
#define MA_NO_GENERATION
16+
#define MA_NO_THREADING
17+
#define MINIAUDIO_IMPLEMENTATION
18+
#include "miniaudio.h"
19+
#include <cstdio>
20+
inline bool funasr_load_audio_16k_mono(const char * path, std::vector<float> & out) {
21+
if (!path) { fprintf(stderr, "audio: null path\n"); return false; }
22+
ma_decoder_config cfg = ma_decoder_config_init(ma_format_f32, 1, 16000); // f32, mono, 16k
23+
ma_decoder dec;
24+
if (ma_decoder_init_file(path, &cfg, &dec) != MA_SUCCESS) {
25+
fprintf(stderr, "audio: failed to open/decode %s (supported: wav/mp3/flac)\n", path);
26+
return false;
27+
}
28+
out.clear();
29+
ma_uint64 nframes = 0;
30+
if (ma_decoder_get_length_in_pcm_frames(&dec, &nframes) == MA_SUCCESS && nframes > 0) {
31+
out.resize(nframes);
32+
ma_uint64 got = 0;
33+
ma_result r = ma_decoder_read_pcm_frames(&dec, out.data(), nframes, &got);
34+
if (r != MA_SUCCESS && r != MA_AT_END) { ma_decoder_uninit(&dec); fprintf(stderr, "audio: decode error\n"); return false; }
35+
out.resize(got);
36+
} else {
37+
// length unknown (e.g. some mp3 streams): read in chunks until EOF
38+
std::vector<float> buf(16000);
39+
for (;;) {
40+
ma_uint64 got = 0;
41+
ma_result r = ma_decoder_read_pcm_frames(&dec, buf.data(), buf.size(), &got);
42+
out.insert(out.end(), buf.begin(), buf.begin() + got);
43+
if (got < buf.size() || (r != MA_SUCCESS && r != MA_AT_END)) break;
44+
}
45+
}
46+
ma_decoder_uninit(&dec);
47+
return !out.empty();
48+
}
49+
#endif

0 commit comments

Comments
 (0)