From eb49f0fcc50c42fbdc6e80c8d7efa81f41333e70 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Wed, 6 Jul 2022 22:17:06 +0000 Subject: [PATCH] Mixer and a few filters --- Makefile | 2 +- source/editor/editor.h | 20 ++--- source/engine/circbuf.c | 7 +- source/engine/datastream.c | 19 ++++- source/engine/datastream.h | 2 + source/engine/dsp.c | 126 ++++++++++++++++++++++++++++++- source/engine/dsp.h | 66 ++++++++++++++++- source/engine/mix.c | 41 +++++------ source/engine/mix.h | 10 +-- source/engine/sound.c | 147 ++++++++++++++++++++++++------------- source/engine/sound.h | 14 +++- 11 files changed, 350 insertions(+), 104 deletions(-) diff --git a/Makefile b/Makefile index 4b87c02..2f192b3 100755 --- a/Makefile +++ b/Makefile @@ -79,7 +79,7 @@ COMPINCLUDE = $(edirs) $(eddirs) $(pindirs) $(bsdirs) -WARNING_FLAGS = -Wall -Wwrite-strings -Wunsupported #-Wall -Wextra -Wwrite-strings -Wno-unused-parameter -Wno-unused-function -Wno-missing-braces -Wno-incompatible-function-pointer-types -Wno-gnu-statement-expression -Wno-complex-component-init -pedantic +WARNING_FLAGS = -Wall -Wwrite-strings -Wunsupported -Wall -Wextra -Wwrite-strings -Wno-unused-parameter -Wno-unused-function -Wno-missing-braces -Wno-incompatible-function-pointer-types -Wno-gnu-statement-expression -Wno-complex-component-init -pedantic diff --git a/source/editor/editor.h b/source/editor/editor.h index 0d9ae41..a623a6f 100755 --- a/source/editor/editor.h +++ b/source/editor/editor.h @@ -22,16 +22,16 @@ struct fileasset { }; struct editorVars { - bool showStats :1 ; - bool showHierarchy :1 ; - bool showLighting :1 ; - bool showGameSettings :1 ; - bool showViewmode :1 ; - bool showDebugMenu :1 ; - bool showAssetMenu :1 ; - bool showREPL :1 ; - bool showExport :1 ; - bool showLevel :1 ; + bool showStats; + bool showHierarchy; + bool showLighting; + bool showGameSettings; + bool showViewmode; + bool showDebugMenu; + bool showAssetMenu; + bool showREPL; + bool showExport; + bool showLevel; }; struct gameproject { diff --git a/source/engine/circbuf.c b/source/engine/circbuf.c index ddd178d..df5f9c0 100644 --- a/source/engine/circbuf.c +++ b/source/engine/circbuf.c @@ -7,7 +7,6 @@ struct circbuf circbuf_init(size_t size, unsigned int len) { struct circbuf new; new.len = powof2(len); - new.len = len; new.data = calloc(sizeof(short), new.len); new.read = new.write = 0; @@ -23,7 +22,7 @@ int cbuf_empty(struct circbuf *buf) { } int cbuf_full(struct circbuf *buf) { - return cbuf_size(buf) == buf->len; + return cbuf_size(buf) >= buf->len; } uint32_t cbuf_mask(struct circbuf *buf, uint32_t n) { @@ -31,13 +30,13 @@ uint32_t cbuf_mask(struct circbuf *buf, uint32_t n) { } void cbuf_push(struct circbuf *buf, short data) { - assert(!cbuf_full(buf)); + //assert(!cbuf_full(buf)); buf->data[cbuf_mask(buf,buf->write++)] = data; } short cbuf_shift(struct circbuf *buf) { - assert(!cbuf_empty(buf)); + //assert(!cbuf_empty(buf)); return buf->data[cbuf_mask(buf, buf->read++)]; } diff --git a/source/engine/datastream.c b/source/engine/datastream.c index 6aa1fb0..d4501da 100755 --- a/source/engine/datastream.c +++ b/source/engine/datastream.c @@ -9,6 +9,8 @@ #include "log.h" #include "texture.h" #include +#include "mix.h" +#include "limits.h" struct mShader *vid_shader; @@ -31,7 +33,12 @@ static void render_frame(plm_t * mpeg, plm_frame_t * frame, void *user) static void render_audio(plm_t * mpeg, plm_samples_t * samples, void *user) { struct datastream *ds = user; - play_raw(ds->audio_device, samples->interleaved, samples->count * 2); + short t; + + for (int i = 0; i < samples->count * CHANNELS; i++) { + t = (short)(samples->interleaved[i] * SHRT_MAX); + cbuf_push(&ds->astream.buf, t*5); + } } struct Texture *ds_maketexture(struct datastream *ds) @@ -62,6 +69,14 @@ void ds_openvideo(struct datastream *ds, const char *video, const char *adriver) plm_get_duration(ds->plm) ); + ds->astream = soundstream_make(); + struct dsp_filter astream_filter; + astream_filter.data = &ds->astream; + astream_filter.filter = soundstream_fillbuf; + first_free_bus(astream_filter); + + printf("Circbuf size is %u.\n", ds->astream.buf.len); + plm_set_video_decode_callback(ds->plm, render_frame, ds); plm_set_audio_decode_callback(ds->plm, render_audio, ds); plm_set_loop(ds->plm, false); @@ -118,7 +133,7 @@ void ds_advance(struct datastream *ds, double s) void ds_seek(struct datastream *ds, double time) { - clear_raw(ds->audio_device); + //clear_raw(ds->audio_device); plm_seek(ds->plm, time, false); } diff --git a/source/engine/datastream.h b/source/engine/datastream.h index e226c95..1edd282 100755 --- a/source/engine/datastream.h +++ b/source/engine/datastream.h @@ -3,6 +3,7 @@ #include #include +#include "sound.h" struct datastream { plm_t *plm; @@ -13,6 +14,7 @@ struct datastream { uint32_t texture_y; uint32_t texture_cb; uint32_t texture_cr; + struct soundstream astream; }; struct Texture; diff --git a/source/engine/dsp.c b/source/engine/dsp.c index 12e2b87..5441d61 100644 --- a/source/engine/dsp.c +++ b/source/engine/dsp.c @@ -3,13 +3,28 @@ #include "sound.h" #include "limits.h" #include "math.h" +#include "stdlib.h" #define PI 3.14159265 -void am_mod(short *a, short *b, short *c, int n) +struct dsp_filter make_dsp(void *data, void (*in)(void *data, short *out, int n)) { + struct dsp_filter new; + new.data = data; + new.filter = in; +} + +void dsp_run(struct dsp_filter filter, short *out, int n) { + filter.filter(filter.data, out, n); +} + +void am_mod(struct dsp_ammod *mod, short *c, int n) { - for (int i = 0; i < n; i++) { - c[i] = (a[i]*b[i])>>15; + dsp_run(mod->ina, mod->abuf, n); + dsp_run(mod->inb, mod->bbuf, n); + + for (int i = 0; i < n*2; i++) { + c[i] = (mod->abuf[i]*mod->bbuf[i])>>15; + //c[i] = mod->abuf[i]; } } @@ -38,10 +53,11 @@ struct wav gen_sine(float amp, float freq, int sr, int ch) for (int j = 0; j < new.ch; j++) { data[i*new.ch+j] = val; - printf("Element %i gets val %i.\n", i*new.frames+j, val); } } + printf("Made sine with %i frames.\n", new.frames); + return new; } @@ -112,4 +128,106 @@ void make_dsp_filter() void dsp_filter(short *in, short *out, int samples, struct dsp_delay *d) { +} + +void dsp_rectify(short *in, short *out, int n) +{ + for (int i = 0; i < n; i++) { + out[i] = abs(in[i]); + } +} + +struct phasor phasor_make(unsigned int sr, float freq) +{ + struct phasor new; + new.sr = sr; + new.cur = 0.f; + new.freq = freq; + + new.cstep = 0; + new.clen = new.sr / new.freq; + new.cache = malloc(new.clen * sizeof(float)); + + for (int i = 0; i < new.clen; i++) { + new.cache[i] = (float)i / new.clen; + } + + return new; +} + +float phasor_step(struct phasor *p) +{ + p->cur += p->freq/p->sr; + if (p->cur >= 1.f) p->cur = 0.f; + return p->cur; + +/* + float ret = p->cache[p->cstep++]; + if (p->cstep ==p->clen) p->cstep = 0; + + return ret; + */ +} + +float sin_phasor(float p) +{ + return sin(2*PI*p); +} + +float square_phasor(float p) +{ + return lround(p); +} + +float saw_phasor(float p) +{ + return 2*p-1; +} + +float tri_phasor(float p) +{ + return 4*(p * 0.5f ? p : (1-p)) - 1; +} + +void osc_fillbuf(struct osc *osc, short *buf, int n) +{ + for (int i = 0; i < n; i++) { + short val = SHRT_MAX * osc->f(phasor_step(&osc->p)); + buf[i*2] = buf[i*2+1] = val; + } +} + +void gen_whitenoise(void *data, short *buf, int n) +{ + for (int i = 0; i < n; i++) { + for (int j = 0; j < 2; j++) { + buf[i*2+j] = (rand()>>15) - USHRT_MAX; + } + } +} + +struct dsp_delay dsp_delay_make(unsigned int ms_delay) +{ + struct dsp_delay new; + new.ms_delay = ms_delay; + + /* Circular buffer size is enough to have the delay */ + unsigned int datasize = ms_delay * CHANNELS * (SAMPLERATE / 1000); + new.buf = circbuf_init(sizeof(short), datasize); + new.buf.write = datasize; + + printf("Buffer size is %u.\n", new.buf.len); + + return new; +} + +void dsp_delay_filbuf(struct dsp_delay *delay, short *buf, int n) +{ + static short cache[BUF_FRAMES*2]; + dsp_run(delay->in, cache, n); + + for (int i = 0; i < n*2; i++) { + cbuf_push(&delay->buf, cache[i] / 2); + buf[i] = cache[i] + cbuf_shift(&delay->buf); + } } \ No newline at end of file diff --git a/source/engine/dsp.h b/source/engine/dsp.h index ca5c106..dd65bdb 100644 --- a/source/engine/dsp.h +++ b/source/engine/dsp.h @@ -1,18 +1,70 @@ #ifndef DSP_H #define DSP_H +#define SAMPLERATE 48000 +#define BUF_FRAMES 4096 +#define CHANNELS 2 +#define MUSIZE 2 + #include "circbuf.h" -void am_mod(short *a, short *b, short *c, int n); + +void dsp_rectify(short *in, short *out, int n); struct dsp_filter { - void (*filter)(short *in, short *out, int samples, void *data); + void (*filter)(void *data, short *out, int samples); void *data; }; struct dsp_delay { unsigned int ms_delay; struct circbuf buf; + struct dsp_filter in; +}; + +struct dsp_delay dsp_delay_make(unsigned int ms_delay); +void dsp_delay_filbuf(struct dsp_delay *delay, short *buf, int n); + +struct dsp_ammod { + struct dsp_filter ina; + struct dsp_filter inb; + short abuf[BUF_FRAMES*2]; + short bbuf[BUF_FRAMES*2]; +}; + +struct dsp_compressor { + +}; + +struct dsp_limiter { + +}; + +struct dsp_hpf { + +}; + +struct dsp_lpf { + +}; + +struct phasor { + unsigned int sr; + float cur; + float freq; + unsigned int clen; + unsigned int cstep; + float *cache; +}; + +struct phasor phasor_make(unsigned int sr, float freq); + +struct osc { + float (*f)(float p); + struct phasor p; + unsigned int frames; + unsigned int frame; + short *cache; }; struct wav; @@ -22,4 +74,14 @@ struct wav gen_square(float amp, float freq, int sr, int ch); struct wav gen_triangle(float amp, float freq, int sr, int ch); struct wav gen_saw(float amp, float freq, int sr, int ch); + +float sin_phasor(float p); +float square_phasor(float p); +float saw_phasor(float p); +float tri_phasor(float p); + +void osc_fillbuf(struct osc *osc, short *buf, int n); + +void am_mod(struct dsp_ammod *mod, short *c, int n); + #endif \ No newline at end of file diff --git a/source/engine/mix.c b/source/engine/mix.c index 53c8e5e..17388b6 100644 --- a/source/engine/mix.c +++ b/source/engine/mix.c @@ -1,42 +1,41 @@ #include "mix.h" #include "stddef.h" - +#include "time.h" #include "sound.h" static struct bus bus[256]; short mastermix[BUF_FRAMES*CHANNELS]; -struct bus *first_free_bus() { +struct bus *first_free_bus(struct dsp_filter in) { for (int i = 0; i < 256; i++) { - if (!bus[i].on) return &bus[i]; + if (!bus[i].on) { + bus[i].on = 1; + bus[i].in = in; + return &bus[i]; + } } return NULL; } -void bus_fill_buffers() { +void bus_fill_buffers(short *master, int n) { + //clock_t sa = clock(); for (int i = 0; i < 256; i++) { - if (!bus[i].on) continue; - - short *s = (short*)bus[i].sound->data->data; - - for (int k = 0; k < BUF_FRAMES; k++) { - for (int j = 0; j < CHANNELS; j++) { - bus[i].buf[k*CHANNELS + j] = s[bus[i].sound->frame++]; - if (bus[i].sound->frame == bus[i].sound->data->frames) { - bus[i].sound->frame = 0; - if (!bus[i].sound->loop) bus[i].on = 0; - } - } - } + if (bus[i].on != 1) continue; + dsp_run(bus[i].in, bus[i].buf, BUF_FRAMES); } + //printf("DSP run took %f.\n", (double)(clock() - sa)/CLOCKS_PER_SEC); - for (int i = 0; i < BUF_FRAMES*CHANNELS; i++) { - mastermix[i] = 0; + //sa = clock(); + + memset(master, 0, BUF_FRAMES*CHANNELS*sizeof(short)); for (int j = 0; j < 256; j++) { if (!bus[j].on) continue; - mastermix[i] += bus[j].buf[i]; + for (int i = 0; i < BUF_FRAMES*CHANNELS; i++) { + master[i] += bus[j].buf[i]; + } } - } + + //printf("Mix took %f.\n", (double)(clock() - sa)/CLOCKS_PER_SEC); } \ No newline at end of file diff --git a/source/engine/mix.h b/source/engine/mix.h index d81bb0c..5e57648 100644 --- a/source/engine/mix.h +++ b/source/engine/mix.h @@ -1,23 +1,21 @@ #ifndef MIX_H #define MIX_H -#define BUF_FRAMES 4096 -#define CHANNELS 2 -#define MUSIZE 2 +#include "dsp.h" struct sound; struct bus { int on; - struct sound *sound; + struct dsp_filter in; short buf[BUF_FRAMES*CHANNELS]; }; extern short mastermix[BUF_FRAMES*CHANNELS]; -struct bus *first_free_bus(); -void bus_fill_buffers(); +struct bus *first_free_bus(struct dsp_filter in); +void bus_fill_buffers(short *master, int n); #endif \ No newline at end of file diff --git a/source/engine/sound.c b/source/engine/sound.c index 2b51705..394de94 100755 --- a/source/engine/sound.c +++ b/source/engine/sound.c @@ -11,7 +11,6 @@ #include "SDL2/SDL.h" #include "mix.h" - #include "dsp.h" #define TSF_IMPLEMENTATION @@ -75,21 +74,7 @@ static int patestCallback(const void *inputBuffer, void *outputBuffer, unsigned /* Cast data passed through stream to our structure. */ short *out = (short*)outputBuffer; - bus_fill_buffers(); - - for (int i = 0; i < framesPerBuffer * 2; i++) { - out[i] = mastermix[i]; - } - - - - if (!vidplaying) return 0; - - for (int i = 0; i < framesPerBuffer; i++) { - out[i*2] += cbuf_shift(&vidbuf) * 5; - out[i*2+1] += cbuf_shift(&vidbuf) * 5; - } - + bus_fill_buffers(outputBuffer, framesPerBuffer); return 0; } @@ -118,6 +103,13 @@ void normalize_gain(struct wav *w, double lv) w->gain = log10((float)tarmax/max) * 20; } +struct osc sin600; +struct osc sin20; +struct dsp_ammod dspammod; +struct dsp_delay dspdel; +struct wav s600wav; +struct sound s600wavsound; + void sound_init() { vidbuf = circbuf_init(sizeof(short), 262144); @@ -139,13 +131,54 @@ void sound_init() //play_sound(&wavsound); - sin440 = gen_sine(0.4f, 30, 48000, 2); + sin440 = gen_sine(0.4f, 30, SAMPLERATE, 2); a440.data = &sin440; a440.loop = 1; - play_sound(&a440); + //play_sound(&a440); printf("Playing wav with %i frames.\n", wavsound.data->frames); + sin600.f = tri_phasor; + sin600.p = phasor_make(SAMPLERATE, 200); + + + + sin20.f = square_phasor; + sin20.p.sr = SAMPLERATE; + sin20.p.freq = 4; + + s600wav = gen_sine(0.6f, 600, SAMPLERATE, CHANNELS); + + s600wavsound.loop = -1; + s600wavsound.data = &s600wav; + + + struct dsp_filter s600; + s600.data = &s600wavsound; + s600.filter = sound_fillbuf; + + struct dsp_filter s20; + s20.data = &sin20; + s20.filter = osc_fillbuf; + + struct dsp_filter am_filter; + + + dspammod.ina = s600; + dspammod.inb = s20; + + am_filter.filter = am_mod; + am_filter.data = &dspammod; + + dspdel = dsp_delay_make(150); + dspdel.in = am_filter; + struct dsp_filter del_filter; + del_filter.filter = dsp_delay_filbuf; + del_filter.data = &dspdel; + + //first_free_bus(s600); + first_free_bus(del_filter); + /* if (!drmp3_init_file(&mp3, "sounds/circus.mp3", NULL)) { YughError("Could not open mp3.",0); @@ -154,7 +187,7 @@ void sound_init() printf("CIrcus mp3 channels: %ui, samplerate: %ui\n", mp3.channels, mp3.sampleRate); */ - PaError err = Pa_Initialize(); + PaError err = Pa_Initialize(); check_pa_err(err); int numDevices = Pa_GetDeviceCount(); @@ -178,7 +211,7 @@ void sound_init() */ //err = Pa_OpenStream(&stream_def, NULL, &outparams, 48000, 4096, paNoFlag, patestCallback, &data); - err = Pa_OpenDefaultStream(&stream_def, 0, 2, paInt16, 48000, 4096, patestCallback, NULL); + err = Pa_OpenDefaultStream(&stream_def, 0, 2, paInt16, SAMPLERATE, BUF_FRAMES, patestCallback, NULL); check_pa_err(err); err = Pa_StartStream(stream_def); @@ -221,13 +254,6 @@ struct sound *make_music(const char *ogg) } -void play_sound(struct sound *sound) -{ - struct bus *b = first_free_bus(); - b->sound = sound; - b->on = 1; - sound->frame = 0; -} void play_music(struct sound *music) { @@ -282,45 +308,22 @@ void audio_init() //audioDriver = SDL_GetAudioDeviceName(0,0); } -void play_raw(int device, void *data, int size) -{ - - float *d = data; - short t; - for (int i = 0; i < size; i++) { - t = (short)(d[i]*32767); - cbuf_push(&vidbuf, t); - } - - vidplaying = 1; - /* - for (int i = 0; i < size; i++) { - short temp = (short)(d[i] * 32767); - cbuf_append(&vidbuf, &temp, 1); - } - */ -} void close_audio_device(int device) { //SDL_CloseAudioDevice(device); } -void clear_raw(int device) -{ - //SDL_ClearQueuedAudio(device); -} - int open_device(const char *adriver) { /* SDL_AudioSpec audio_spec; SDL_memset(&audio_spec, 0, sizeof(audio_spec)); - audio_spec.freq = 48000; + audio_spec.freq = SAMPLERATE; audio_spec.format = AUDIO_F32; audio_spec.channels = 2; - audio_spec.samples = 4096; + audio_spec.samples = BUF_FRAMES; int dev = (int) SDL_OpenAudioDevice(adriver, 0, &audio_spec, NULL, 0); SDL_PauseAudioDevice(dev, 0); @@ -328,3 +331,43 @@ int open_device(const char *adriver) */ return 0; } + +void play_sound(struct sound *sound) +{ + sound->frame = 0; + //struct bus *b = first_free_bus(sound, sound_fillbuf); +} + + +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]; + } + s->frame++; + if (s->frame == s->data->frames) { + s->frame = 0; + if (s->loop > 0) { + s->loop--; + } + } + } +} + +struct soundstream soundstream_make() +{ + struct soundstream new; + new.buf = circbuf_init(sizeof(short), BUF_FRAMES*CHANNELS*2); + return new; +} + +void soundstream_fillbuf(struct soundstream *s, short *buf, int n) +{ + int max = s->buf.write - s->buf.read; + for (int i = 0; i < n*CHANNELS; i++) { + buf[i] = (i < max) ? cbuf_shift(&s->buf) : 0; + } +} + diff --git a/source/engine/sound.h b/source/engine/sound.h index 2ca2d73..e4ac134 100755 --- a/source/engine/sound.h +++ b/source/engine/sound.h @@ -1,6 +1,8 @@ #ifndef SOUND_H #define SOUND_H +#include "circbuf.h" + struct Mix_Chunk { int i; }; @@ -15,6 +17,12 @@ enum MUS { MUS_PAUSE }; +struct soundstream { + struct circbuf buf; +}; + +struct soundstream soundstream_make(); + struct sound { int loop; int frame; @@ -36,6 +44,8 @@ void sound_init(); void audio_open(const char *device); void audio_close(); +void sound_fillbuf(struct sound *s, short *buf, int n); + struct sound *make_sound(const char *wav); struct sound *make_music(const char *ogg); @@ -52,9 +62,9 @@ void music_resume(); void music_pause(); void music_stop(); +void soundstream_fillbuf(struct soundstream *stream, short *buf, int n); + void close_audio_device(int device); -void clear_raw(int device); -void play_raw(int device, void *data, int size); int open_device(const char *adriver); void audio_init();