From 5da19ec407e5f187bb0ff17e0cd9cce7d9e46af7 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 16 Jan 2023 05:27:28 +0000 Subject: [PATCH] Optimize busses; add samplerate changing library --- Makefile | 2 +- source/engine/ffi.c | 4 +-- source/engine/sound.c | 72 +++++++++++++++++++++++++++---------- source/engine/sound.h | 8 ++--- source/engine/sound/dsp.c | 1 + source/engine/sound/mix.c | 56 ++++++++++++++--------------- source/engine/sound/music.c | 6 ++-- source/engine/sound/music.h | 1 + 8 files changed, 93 insertions(+), 57 deletions(-) diff --git a/Makefile b/Makefile index f14f20b..15d6f68 100755 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ ifeq ($(OS), WIN32) EXT = .exe else LINKER_FLAGS = $(QFLAGS) -L/usr/local/lib - ELIBS = engine pthread yughc portaudio asound glfw3 c m dl + ELIBS = engine pthread yughc portaudio asound glfw3 c m dl samplerate CLIBS = endif diff --git a/source/engine/ffi.c b/source/engine/ffi.c index ae47664..3a81293 100644 --- a/source/engine/ffi.c +++ b/source/engine/ffi.c @@ -120,11 +120,11 @@ duk_ret_t duk_cmd(duk_context *duk) { break; case 14: - play_sound(make_sound(duk_to_string(duk, 1))); + play_oneshot(make_sound(duk_to_string(duk, 1))); break; case 15: - + music_stop(); break; case 16: diff --git a/source/engine/sound.c b/source/engine/sound.c index 7b0753e..78e7861 100644 --- a/source/engine/sound.c +++ b/source/engine/sound.c @@ -9,6 +9,8 @@ #include "music.h" #include "stb_vorbis.h" +#include "samplerate.h" + #include "stb_ds.h" #include "mix.h" @@ -47,27 +49,53 @@ void new_samplerate(short *in, short *out, int n, int ch, int sr_in, int sr_out) */ } -struct wav change_samplerate(struct wav w, int rate) +static struct wav change_channels(struct wav w, int ch) { - //int samples = sizeof(short) * w.ch * w.frames; - //short *new = malloc(samples); - //new_samplerate(w.data, new, + short *data = w.data; + int samples = ch * w.frames; + short *new = malloc(sizeof(short)*samples); + if (ch > w.ch) { + /* Sets all new channels equal to the first one */ + for (int i = 0; i < w.frames; i++) { + for (int j = 0; j < ch; j++) + new[i*ch+j] = data[i]; + } + } else { + /* Simple method; just use first N channels present in wav */ + for (int i = 0; i < w.frames; i++) + for (int j = 0; j < ch; j++) + new[i*ch+j] = data[i*ch+j]; + } + free (w.data); + w.data = new; + return w; +} - //SDL_AudioStream *stream = SDL_NewAudioStream(AUDIO_S16, w.ch, w.samplerate, AUDIO_S16, w.ch, rate); - //SDL_AudioStreamPut(stream, w.data, w.frames*w.ch*sizeof(short)); +static struct wav change_samplerate(struct wav w, int rate) +{ + float ratio = (float)rate/w.samplerate; + int outframes = w.frames * ratio; + SRC_DATA ssrc; + float floatdata[w.frames*w.ch]; + src_short_to_float_array(w.data, floatdata, w.frames*w.ch); + float resampled[w.ch*outframes]; - int oldframes = w.frames; - w.frames *= (float)rate/w.samplerate; - int samples = sizeof(short) * w.ch * w.frames; - w.samplerate = rate; - short *new = malloc(samples); - //SDL_AudioStreamGet(stream, new, samples); + ssrc.data_in = floatdata; + ssrc.data_out = resampled; + ssrc.input_frames = w.frames; + ssrc.output_frames = outframes; + ssrc.src_ratio = ratio; + + src_simple(&ssrc, SRC_SINC_BEST_QUALITY, w.ch); + + short *newdata = malloc(sizeof(short)*outframes*w.ch); + src_float_to_short_array(resampled, newdata, outframes*w.ch); free(w.data); - w.data = new; - //SDL_FreeAudioStream(stream); + w.data = newdata; + w.samplerate = rate; return w; } @@ -165,11 +193,17 @@ struct wav *make_sound(const char *wav) struct wav mwav; mwav.data = drwav_open_file_and_read_pcm_frames_s16(wav, &mwav.ch, &mwav.samplerate, &mwav.frames, NULL); - if (mwav->samplerate != SAMPLERATE) { - YughInfo("Changing samplerate of %s.", wav); + + if (mwav.samplerate != SAMPLERATE) { + YughInfo("Changing samplerate of %s from %d to %d.", wav, mwav.samplerate, 48000); mwav = change_samplerate(mwav, 48000); } + if (mwav.ch != CHANNELS) { + YughInfo("Changing channels of %s from %d to %d.", wav, mwav.ch, CHANNELS); + //mwav = change_channels(mwav, CHANNELS); + } + mwav.gain = 1.f; struct wav *newwav = malloc(sizeof(*newwav)); @@ -205,6 +239,7 @@ void play_oneshot(struct wav *wav) { new->bus = first_free_bus(dsp_filter(new, sound_fillbuf)); new->playing=1; new->loop=0; + new->frame = 0; } struct sound *play_sound(struct wav *wav) @@ -301,9 +336,7 @@ void sound_fillbuf(struct sound *s, short *buf, int n) short *in = s->data->data; for (int i = 0; i < n; i++) { - for (int j = 0; j < 2; j++) { - buf[i*2+j] = in[s->frame+j] * gainmult; - } + for (int j = 0; j < CHANNELS; j++) buf[i*CHANNELS+j] = in[s->frame+j] * gainmult; s->frame++; if (s->frame == s->data->frames) { @@ -313,6 +346,7 @@ void sound_fillbuf(struct sound *s, short *buf, int n) s->frame = 0; } else { bus_free(s->bus); + return; } } } diff --git a/source/engine/sound.h b/source/engine/sound.h index ccc587d..66edb52 100644 --- a/source/engine/sound.h +++ b/source/engine/sound.h @@ -2,7 +2,6 @@ #define SOUND_H struct circbuf; -struct SDL_AudioStream; struct Mix_Chunk { int i; @@ -23,16 +22,15 @@ struct soundstream { }; struct soundconvstream { - // SDL_AudioStream *srconv; void *data; }; struct soundstream *soundstream_make(); -/* A playing sound; +/* A playing sound */ struct sound { - int loop; - unsigned int frame; + int loop; /* How many times to loop */ + unsigned int frame; /* Pointing to the current frame on the wav */ int playing; float gain; diff --git a/source/engine/sound/dsp.c b/source/engine/sound/dsp.c index 4985753..9074d42 100644 --- a/source/engine/sound/dsp.c +++ b/source/engine/sound/dsp.c @@ -160,6 +160,7 @@ struct dsp_filter dsp_filter(void *data, void (*filter)(void *data, short *out, struct dsp_filter new; new.data = data; new.filter = filter; + new.inputs = 0; return new; } diff --git a/source/engine/sound/mix.c b/source/engine/sound/mix.c index 8d36401..24d823e 100644 --- a/source/engine/sound/mix.c +++ b/source/engine/sound/mix.c @@ -4,10 +4,12 @@ #include "sound.h" #include "dsp.h" #include +#include "log.h" static struct bus bus[256]; static int first = 0; /* First bus available */ -static int first_on = -1; +//static struct bus *first_on = NULL; +static int first_on = -1; /* First bus to fill buffer with */ short mastermix[BUF_FRAMES*CHANNELS]; void mixer_init() { @@ -22,46 +24,44 @@ void mixer_init() { struct bus *first_free_bus(struct dsp_filter in) { if (first == -1) return NULL; - struct bus *ret = bus[first]; - first = ret->next; - ret->on = 1; - ret->in = in; + int ret = first; + first = bus[ret].next; - ret->next = first_on; - first_on = ret->id; + bus[ret].on = 1; + bus[ret].in = in; - return ret; + if (first_on != -1) bus[first_on].prev = ret; + + bus[ret].next = first_on; + bus[ret].prev = -1; + first_on = ret; + + return &bus[ret]; } -void bus_free(struct bus *bus) +void bus_free(struct bus *b) { - bus->next = first; - bus->on = 0; - first = bus->id; + if (first_on == b->id) first_on = b->next; + if (b->next != -1) bus[b->next].prev = b->prev; + if (b->prev != -1) bus[b->prev].next = b->next; + + b->next = first; + first = b->id; + b->on = 0; } void bus_fill_buffers(short *master, int n) { - int curbus = first_one + int curbus = first_on; + if (curbus == -1) return; memset(master, 0, BUF_FRAMES*CHANNELS*sizeof(short)); - while (bus[curbus].next != -1) { + + while (curbus != -1) { + int nextbus = bus[curbus].next; /* Save this in case busses get changed during fill */ dsp_run(bus[curbus].in, bus[curbus].buf, BUF_FRAMES); for (int i = 0; i < BUF_FRAMES*CHANNELS; i++) master[i] += bus[curbus].buf[i]; - curbus = bus[curbus].next; + curbus = nextbus; } - /* - for (int i = 0; i < 256; i++) { - if (bus[i].on != 1) continue; - dsp_run(bus[i].in, bus[i].buf, BUF_FRAMES); - } - - for (int j = 0; j < 256; j++) { - if (!bus[j].on) continue; - for (int i = 0; i < BUF_FRAMES*CHANNELS; i++) { - master[i] += bus[j].buf[i]; - } - } - */ } diff --git a/source/engine/sound/music.c b/source/engine/sound/music.c index 64b9f3c..276d270 100644 --- a/source/engine/sound/music.c +++ b/source/engine/sound/music.c @@ -61,6 +61,8 @@ void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n) dsp_pan(&music_pan, out, n); } +struct bus *musicbus; + void play_song(const char *midi, const char *sf) { gsong.midi = tml_load_filename(midi); @@ -85,7 +87,7 @@ void play_song(const char *midi, const char *sf) cursong.data = &gsong; cursong.filter = dsp_midi_fillbuf; - first_free_bus(cursong); + musicbus = first_free_bus(cursong); } @@ -96,7 +98,7 @@ void music_play() void music_stop() { - + bus_free(musicbus); } void music_volume() diff --git a/source/engine/sound/music.h b/source/engine/sound/music.h index 1083d30..3649e75 100644 --- a/source/engine/sound/music.h +++ b/source/engine/sound/music.h @@ -14,6 +14,7 @@ struct dsp_midi_song { extern float music_pan; void play_song(const char *midi, const char *sf); +void music_stop(); void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n); #endif