Skip to content

Commit c8a2caa

Browse files
committedJan 23, 2025
Use miniaudio for direct decoding flac, mp3, ogg and wav
1 parent 7ffcd05 commit c8a2caa

File tree

11 files changed

+98963
-8919
lines changed

11 files changed

+98963
-8919
lines changed
 

‎Makefile

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,6 @@ samples:
1818
@wget --quiet --show-progress -O samples/mm1.wav https://cdn.openai.com/whisper/draft-20220913a/micro-machines.wav
1919
@wget --quiet --show-progress -O samples/a13.mp3 https://upload.wikimedia.org/wikipedia/commons/transcoded/6/6f/Apollo13-wehaveaproblem.ogg/Apollo13-wehaveaproblem.ogg.mp3
2020
@wget --quiet --show-progress -O samples/diffusion2023-07-03.flac https://archive.org/download/diffusion2023-07-03/diffusion2023-07-03.flac
21-
@echo "Converting to 16-bit WAV ..."
22-
@ffmpeg -loglevel -0 -y -i samples/gb0.ogg -ar 16000 -ac 1 -c:a pcm_s16le samples/gb0.wav
23-
@ffmpeg -loglevel -0 -y -i samples/gb1.ogg -ar 16000 -ac 1 -c:a pcm_s16le samples/gb1.wav
24-
@ffmpeg -loglevel -0 -y -i samples/hp0.ogg -ar 16000 -ac 1 -c:a pcm_s16le samples/hp0.wav
25-
@rm samples/*.ogg
26-
@ffmpeg -loglevel -0 -y -i samples/mm1.wav -ar 16000 -ac 1 -c:a pcm_s16le samples/mm0.wav
27-
@rm samples/mm1.wav
28-
@ffmpeg -loglevel -0 -y -i samples/a13.mp3 -ar 16000 -ac 1 -c:a pcm_s16le -ss 00:00:00 -to 00:00:30 samples/a13.wav
29-
@rm samples/a13.mp3
30-
@ffmpeg -loglevel -0 -y -i samples/diffusion2023-07-03.flac -ar 16000 -ac 1 -c:a pcm_s16le samples/diffusion2023-07-03.wav
31-
@rm samples/diffusion2023-07-03.flac
3221

3322
#
3423
# Models
@@ -59,7 +48,7 @@ tiny.en tiny base.en base small.en small medium.en medium large-v1 large-v2 larg
5948
@echo "Running $@ on all samples in ./samples ..."
6049
@echo "==============================================="
6150
@echo ""
62-
@for f in samples/*.wav; do \
51+
@for f in samples/*$(.flac .mp3 .ogg .wav); do \
6352
echo "----------------------------------------------" ; \
6453
echo "[+] Running $@ on $$f ... (run 'ffplay $$f' to listen)" ; \
6554
echo "----------------------------------------------" ; \

‎README.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,6 @@ The command downloads the `base.en` model converted to custom `ggml` format and
9292

9393
For detailed usage instructions, run: `./build/bin/whisper-cli -h`
9494

95-
Note that the [whisper-cli](examples/cli) example currently runs only with 16-bit WAV files, so make sure to convert your input before running the tool.
96-
For example, you can use `ffmpeg` like this:
97-
98-
```bash
99-
ffmpeg -i input.mp3 -ar 16000 -ac 1 -c:a pcm_s16le output.wav
100-
```
101-
10295
## More audio samples
10396

10497
If you want some extra audio samples to play with, simply run:
@@ -107,7 +100,7 @@ If you want some extra audio samples to play with, simply run:
107100
make -j samples
108101
```
109102

110-
This will download a few more audio files from Wikipedia and convert them to 16-bit WAV format via `ffmpeg`.
103+
This will download a few more audio files from Wikipedia.
111104

112105
You can download and run the other models as follows:
113106

‎examples/addon.node/addon.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ int run(whisper_params &params, std::vector<std::vector<std::string>> &result) {
171171

172172
// read the input audio file if params.pcmf32 is not provided
173173
if (params.pcmf32.empty()) {
174-
if (!::read_wav(fname_inp, pcmf32, pcmf32s, params.diarize)) {
175-
fprintf(stderr, "error: failed to read WAV file '%s'\n", fname_inp.c_str());
174+
if (!::read_audio_data(fname_inp, pcmf32, pcmf32s, params.diarize)) {
175+
fprintf(stderr, "error: failed to read audio file '%s'\n", fname_inp.c_str());
176176
continue;
177177
}
178178
} else {

‎examples/cli/cli.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ static bool whisper_params_parse(int argc, char ** argv, whisper_params & params
194194

195195
static void whisper_print_usage(int /*argc*/, char ** argv, const whisper_params & params) {
196196
fprintf(stderr, "\n");
197-
fprintf(stderr, "usage: %s [options] file0.wav file1.wav ...\n", argv[0]);
197+
fprintf(stderr, "usage: %s [options] file0 file1 ...\n", argv[0]);
198+
fprintf(stderr, "supported audio formats: flac, mp3, ogg, wav\n");
198199
fprintf(stderr, "\n");
199200
fprintf(stderr, "options:\n");
200201
fprintf(stderr, " -h, --help [default] show this help message and exit\n");
@@ -239,7 +240,7 @@ static void whisper_print_usage(int /*argc*/, char ** argv, const whisper_params
239240
fprintf(stderr, " -dl, --detect-language [%-7s] exit after automatically detecting language\n", params.detect_language ? "true" : "false");
240241
fprintf(stderr, " --prompt PROMPT [%-7s] initial prompt (max n_text_ctx/2 tokens)\n", params.prompt.c_str());
241242
fprintf(stderr, " -m FNAME, --model FNAME [%-7s] model path\n", params.model.c_str());
242-
fprintf(stderr, " -f FNAME, --file FNAME [%-7s] input WAV file path\n", "");
243+
fprintf(stderr, " -f FNAME, --file FNAME [%-7s] input audio file path\n", "");
243244
fprintf(stderr, " -oved D, --ov-e-device DNAME [%-7s] the OpenVINO device used for encode inference\n", params.openvino_encode_device.c_str());
244245
fprintf(stderr, " -dtw MODEL --dtw MODEL [%-7s] compute token-level timestamps\n", params.dtw.c_str());
245246
fprintf(stderr, " -ls, --log-score [%-7s] log best decoder scores of tokens\n", params.log_score?"true":"false");
@@ -1057,8 +1058,8 @@ int main(int argc, char ** argv) {
10571058
std::vector<float> pcmf32; // mono-channel F32 PCM
10581059
std::vector<std::vector<float>> pcmf32s; // stereo-channel F32 PCM
10591060

1060-
if (!::read_wav(fname_inp, pcmf32, pcmf32s, params.diarize)) {
1061-
fprintf(stderr, "error: failed to read WAV file '%s'\n", fname_inp.c_str());
1061+
if (!::read_audio_data(fname_inp, pcmf32, pcmf32s, params.diarize)) {
1062+
fprintf(stderr, "error: failed to read audio file '%s'\n", fname_inp.c_str());
10621063
continue;
10631064
}
10641065

‎examples/common.cpp

Lines changed: 45 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,17 @@
44

55
// third-party utilities
66
// use your favorite implementations
7-
#define DR_WAV_IMPLEMENTATION
8-
#include "dr_wav.h"
7+
#define STB_VORBIS_HEADER_ONLY
8+
#include "stb_vorbis.c" /* Enables Vorbis decoding. */
9+
10+
#define MA_NO_DEVICE_IO
11+
#define MA_NO_THREADING
12+
#define MA_NO_ENCODING
13+
#define MA_NO_GENERATION
14+
#define MA_NO_RESOURCE_MANAGER
15+
#define MA_NO_NODE_GRAPH
16+
#define MINIAUDIO_IMPLEMENTATION
17+
#include "miniaudio.h"
918

1019
#include <cmath>
1120
#include <cstring>
@@ -639,9 +648,14 @@ bool is_wav_buffer(const std::string buf) {
639648
return true;
640649
}
641650

642-
bool read_wav(const std::string & fname, std::vector<float>& pcmf32, std::vector<std::vector<float>>& pcmf32s, bool stereo) {
643-
drwav wav;
644-
std::vector<uint8_t> wav_data; // used for pipe input from stdin or ffmpeg decoding output
651+
bool read_audio_data(const std::string & fname, std::vector<float>& pcmf32, std::vector<std::vector<float>>& pcmf32s, bool stereo) {
652+
std::vector<uint8_t> audio_data; // used for pipe input from stdin or ffmpeg decoding output
653+
654+
ma_result result;
655+
ma_decoder_config decoder_config;
656+
ma_decoder decoder;
657+
658+
decoder_config = ma_decoder_config_init(ma_format_f32, stereo ? 2 : 1, COMMON_SAMPLE_RATE);
645659

646660
if (fname == "-") {
647661
{
@@ -656,93 +670,55 @@ bool read_wav(const std::string & fname, std::vector<float>& pcmf32, std::vector
656670
if (n == 0) {
657671
break;
658672
}
659-
wav_data.insert(wav_data.end(), buf, buf + n);
673+
audio_data.insert(audio_data.end(), buf, buf + n);
660674
}
661675
}
662676

663-
if (drwav_init_memory(&wav, wav_data.data(), wav_data.size(), nullptr) == false) {
664-
fprintf(stderr, "error: failed to open WAV file from stdin\n");
677+
if (ma_decoder_init_memory(audio_data.data(), audio_data.size(), &decoder_config, &decoder) != MA_SUCCESS) {
678+
fprintf(stderr, "Error: failed to open audio data from stdin\n");
665679
return false;
666-
}
680+
}
667681

668-
fprintf(stderr, "%s: read %zu bytes from stdin\n", __func__, wav_data.size());
682+
fprintf(stderr, "%s: read %zu bytes from stdin\n", __func__, audio_data.size());
669683
}
670684
else if (is_wav_buffer(fname)) {
671-
if (drwav_init_memory(&wav, fname.c_str(), fname.size(), nullptr) == false) {
672-
fprintf(stderr, "error: failed to open WAV file from fname buffer\n");
685+
if (ma_decoder_init_memory(audio_data.data(), audio_data.size(), &decoder_config, &decoder) != MA_SUCCESS) {
686+
fprintf(stderr, "Error: failed to open audio data from fname buffer\n");
673687
return false;
674-
}
688+
}
675689
}
676-
else if (drwav_init_file(&wav, fname.c_str(), nullptr) == false) {
690+
else if (ma_decoder_init_file(fname.c_str(), &decoder_config, &decoder) != MA_SUCCESS) {
677691
#if defined(WHISPER_FFMPEG)
678-
if (ffmpeg_decode_audio(fname, wav_data) != 0) {
692+
if (ffmpeg_decode_audio(fname, audio_data) != 0) {
679693
fprintf(stderr, "error: failed to ffmpeg decode '%s' \n", fname.c_str());
680694
return false;
681695
}
682-
if (drwav_init_memory(&wav, wav_data.data(), wav_data.size(), nullptr) == false) {
696+
if (ma_decoder_init_memory(audio_data.data(), audio_data.size(), &decoder_config, &decoder) != MA_SUCCESS) {
683697
fprintf(stderr, "error: failed to read wav data as wav \n");
684698
return false;
685699
}
686700
#else
687-
fprintf(stderr, "error: failed to open '%s' as WAV file\n", fname.c_str());
701+
fprintf(stderr, "error: failed to open '%s' file\n", fname.c_str());
688702
return false;
689703
#endif
690704
}
691705

692-
if (wav.channels != 1 && wav.channels != 2) {
693-
fprintf(stderr, "%s: WAV file '%s' must be mono or stereo\n", __func__, fname.c_str());
694-
drwav_uninit(&wav);
695-
return false;
696-
}
697-
698-
if (stereo && wav.channels != 2) {
699-
fprintf(stderr, "%s: WAV file '%s' must be stereo for diarization\n", __func__, fname.c_str());
700-
drwav_uninit(&wav);
701-
return false;
702-
}
703-
704-
if (wav.sampleRate != COMMON_SAMPLE_RATE) {
705-
fprintf(stderr, "%s: WAV file '%s' must be %i kHz\n", __func__, fname.c_str(), COMMON_SAMPLE_RATE/1000);
706-
drwav_uninit(&wav);
707-
return false;
708-
}
709-
710-
if (wav.bitsPerSample != 16) {
711-
fprintf(stderr, "%s: WAV file '%s' must be 16-bit\n", __func__, fname.c_str());
712-
drwav_uninit(&wav);
713-
return false;
714-
}
715-
716-
const uint64_t n = wav_data.empty() ? wav.totalPCMFrameCount : wav_data.size()/(wav.channels*wav.bitsPerSample/8);
706+
ma_uint64 frame_count;
707+
ma_uint64 frames_read;
717708

718-
std::vector<int16_t> pcm16;
719-
pcm16.resize(n*wav.channels);
720-
drwav_read_pcm_frames_s16(&wav, n, pcm16.data());
721-
drwav_uninit(&wav);
722-
723-
// convert to mono, float
724-
pcmf32.resize(n);
725-
if (wav.channels == 1) {
726-
for (uint64_t i = 0; i < n; i++) {
727-
pcmf32[i] = float(pcm16[i])/32768.0f;
728-
}
729-
} else {
730-
for (uint64_t i = 0; i < n; i++) {
731-
pcmf32[i] = float(pcm16[2*i] + pcm16[2*i + 1])/65536.0f;
732-
}
733-
}
709+
ma_decoder_get_length_in_pcm_frames(&decoder, &frame_count);
710+
pcmf32.resize(stereo ? frame_count*2 : frame_count);
711+
ma_decoder_read_pcm_frames(&decoder, pcmf32.data(), frame_count, &frames_read);
734712

735713
if (stereo) {
736-
// convert to stereo, float
737-
pcmf32s.resize(2);
738-
739-
pcmf32s[0].resize(n);
740-
pcmf32s[1].resize(n);
741-
for (uint64_t i = 0; i < n; i++) {
742-
pcmf32s[0][i] = float(pcm16[2*i])/32768.0f;
743-
pcmf32s[1][i] = float(pcm16[2*i + 1])/32768.0f;
714+
pcmf32s[0].resize(frame_count);
715+
pcmf32s[1].resize(frame_count);
716+
for (uint64_t i = 0; i < frame_count; i++) {
717+
pcmf32s[0][i] = pcmf32[2*i];
718+
pcmf32s[1][i] = pcmf32[2*i + 1];
744719
}
745720
}
721+
ma_decoder_uninit(&decoder);
746722

747723
return true;
748724
}
@@ -909,3 +885,6 @@ bool speak_with_file(const std::string & command, const std::string & text, cons
909885
}
910886
return true;
911887
}
888+
889+
#undef STB_VORBIS_HEADER_ONLY
890+
#include "stb_vorbis.c"

‎examples/common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ bool is_wav_buffer(const std::string buf);
143143
// fname can be a buffer of WAV data instead of a filename
144144
// The sample rate of the audio must be equal to COMMON_SAMPLE_RATE
145145
// If stereo flag is set and the audio has 2 channels, the pcmf32s will contain 2 channel PCM
146-
bool read_wav(
146+
bool read_audio_data(
147147
const std::string & fname,
148148
std::vector<float> & pcmf32,
149149
std::vector<std::vector<float>> & pcmf32s,

0 commit comments

Comments
 (0)
Failed to load comments.