Mono & pan

This commit is contained in:
John Alanbrook 2022-07-12 04:21:57 +00:00
parent a892cb1180
commit afc38d91c3
9 changed files with 161 additions and 13 deletions

View file

@ -91,7 +91,7 @@ void ds_openvideo(struct datastream *ds, const char *video, const char *adriver)
fir->in = astream_filter; fir->in = astream_filter;
*/ */
first_free_bus(astream_filter); //first_free_bus(astream_filter);
plm_set_video_decode_callback(ds->plm, render_frame, ds); plm_set_video_decode_callback(ds->plm, render_frame, ds);
plm_set_audio_decode_callback(ds->plm, render_audio, ds); plm_set_audio_decode_callback(ds->plm, render_audio, ds);

View file

@ -526,3 +526,107 @@ void dsp_reverb_fillbuf(struct dsp_reverb *r, short *out, int n)
{ {
} }
struct dsp_filter dsp_make_compressor()
{
struct dsp_filter filter;
struct dsp_compressor new;
new.ratio = 4000;
new.atk = 50;
new.rls = 250;
new.target = 0.f;
new.threshold = -3.f;
new.atk_tau = tau2pole(new.atk / 3000.f);
new.rls_tau = tau2pole(new.rls / 3000.f);
struct dsp_compressor *c = malloc(sizeof(*c));
*c = new;
filter.data = c;
filter.filter = dsp_compressor_fillbuf;
return filter;
}
void dsp_compressor_fillbuf(struct dsp_compressor *comp, short *out, int n)
{
float val;
float db;
db = comp->target * (val - comp->threshold) / comp->ratio;
for (int i = 0; i < n; i++) {
val = short2db(out[i*CHANNELS]);
if (val < comp->threshold) {
comp->target = comp->rls_tau * comp->target;
val += db;
} else {
comp->target = (1 - comp->atk_tau) + comp->atk_tau * comp->target; // TODO: Bake in the 1 - atk_tau
val -= db;
}
// Apply same compression to both channels
out[i*CHANNELS] = out[i*CHANNELS+1] = db2short(val) * ( out[i*CHANNELS] > 0 ? 1 : -1);
}
}
void dsp_pan(float *deg, short *out, int n)
{
if (*deg < -100) *deg = -100.f;
else if (*deg > 100) *deg = 100.f;
if (*deg == 0.f) return;
float db1, db2;
float pct = *deg / 100.f;
if (*deg > 0) {
db1 = pct2db(1 - pct);
db2 = pct2db(pct);
} else {
db1 = pct2db(1 + pct);
db2 = pct2db(-1*pct);
}
for (int i = 0; i < n; i++) {
double pct = *deg / 100.f;
short L = out[i*CHANNELS];
short R = out[i*CHANNELS +1];
if (*deg > 0) {
out[i*CHANNELS] = short_gain(L, db1);
out[i*CHANNELS+1] = (R + short_gain(L, db2)) / 2;
continue;
}
out[i*CHANNELS+1] = short_gain(R, db1);
out[i*CHANNELS] = short_gain(L, db1) + short_gain(R, db2);
}
}
void dsp_mono(void *p, short *out, int n)
{
for (int i = 0; i < n; i++) {
short val = (out[i*CHANNELS] + out[i*CHANNELS+1]) / 2;
for (int j = 0; j < CHANNELS; j++)
out[i*CHANNELS+j] = val;
}
}

View file

@ -77,7 +77,13 @@ struct dsp_ammod {
}; };
struct dsp_compressor { struct dsp_compressor {
double ratio;
double threshold;
float target;
unsigned int atk; /* Milliseconds */
double atk_tau;
unsigned int rls; /* MIlliseconds */
double rls_tau;
}; };
struct dsp_filter dsp_make_compressor(); struct dsp_filter dsp_make_compressor();
@ -137,4 +143,8 @@ struct dsp_reverb {
struct dsp_filter make_reverb(); struct dsp_filter make_reverb();
void dsp_reverb_fillbuf(struct dsp_reverb *r, short *out, int n); void dsp_reverb_fillbuf(struct dsp_reverb *r, short *out, int n);
void dsp_pan(float *deg, short *out, int n);
void dsp_mono(void *p, short *out, int n);
#endif #endif

View file

@ -19,14 +19,10 @@ struct bus *first_free_bus(struct dsp_filter in) {
} }
void bus_fill_buffers(short *master, int n) { void bus_fill_buffers(short *master, int n) {
//clock_t sa = clock();
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++) {
if (bus[i].on != 1) continue; if (bus[i].on != 1) continue;
dsp_run(bus[i].in, bus[i].buf, BUF_FRAMES); dsp_run(bus[i].in, bus[i].buf, BUF_FRAMES);
} }
//printf("DSP run took %f.\n", (double)(clock() - sa)/CLOCKS_PER_SEC);
//sa = clock();
memset(master, 0, BUF_FRAMES*CHANNELS*sizeof(short)); memset(master, 0, BUF_FRAMES*CHANNELS*sizeof(short));
@ -36,6 +32,4 @@ void bus_fill_buffers(short *master, int n) {
master[i] += bus[j].buf[i]; master[i] += bus[j].buf[i];
} }
} }
//printf("Mix took %f.\n", (double)(clock() - sa)/CLOCKS_PER_SEC);
} }

View file

@ -12,6 +12,12 @@ struct bus {
short buf[BUF_FRAMES*CHANNELS]; short buf[BUF_FRAMES*CHANNELS];
}; };
struct listener {
float x;
float y;
float z;
};
extern short mastermix[BUF_FRAMES*CHANNELS]; extern short mastermix[BUF_FRAMES*CHANNELS];
struct bus *first_free_bus(struct dsp_filter in); struct bus *first_free_bus(struct dsp_filter in);

View file

@ -11,6 +11,8 @@
struct dsp_filter cursong; struct dsp_filter cursong;
struct dsp_midi_song gsong; struct dsp_midi_song gsong;
float music_pan = 0.f;
void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n) void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n)
{ {
short *o = (short*)out; short *o = (short*)out;
@ -54,12 +56,14 @@ void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n)
} }
song->midi = midi; song->midi = midi;
dsp_pan(&music_pan, out, n);
} }
void play_song(const char *midi, const char *sf) void play_song(const char *midi, const char *sf)
{ {
gsong.midi = tml_load_filename("sounds/littlewonder.mid"); gsong.midi = tml_load_filename("sounds/one-winged-angel.mid");
gsong.sf = tsf_load_filename("sounds/ff7.sf2"); gsong.sf = tsf_load_filename("sounds/mario.sf2");
gsong.time = 0.f; gsong.time = 0.f;
tsf_set_output(gsong.sf, TSF_STEREO_INTERLEAVED, SAMPLERATE, 0.f); tsf_set_output(gsong.sf, TSF_STEREO_INTERLEAVED, SAMPLERATE, 0.f);

View file

@ -11,6 +11,8 @@ struct dsp_midi_song {
tml_message *midi; tml_message *midi;
}; };
extern float music_pan;
void play_song(const char *midi, const char *sf); void play_song(const char *midi, const char *sf);
void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n); void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n);

View file

@ -91,7 +91,7 @@ static PaStream *stream_def;
void normalize_gain(struct wav *w, double lv) void normalize_gain(struct wav *w, double lv)
{ {
short tarmax = pow(10, lv/20.f) * SHRT_MAX; short tarmax = db2short(lv);
short max = 0; short max = 0;
short *s = w->data; short *s = w->data;
for (int i = 0; i < w->frames; i++) { for (int i = 0; i < w->frames; i++) {
@ -180,7 +180,7 @@ void sound_init()
dspammod.ina = s600; dspammod.ina = s600;
dspammod.inb = s20; dspammod.inb = s20;
// first_free_bus(am_filter); //first_free_bus(am_filter);
struct dsp_filter wn; struct dsp_filter wn;
wn.filter = gen_pinknoise; wn.filter = gen_pinknoise;
@ -227,7 +227,7 @@ void sound_init()
//play_song("", ""); play_song("", "");
} }
void audio_open(const char *device) void audio_open(const char *device)
@ -381,3 +381,24 @@ void soundstream_fillbuf(struct soundstream *s, short *buf, int n)
} }
} }
float short2db(short val)
{
return 20*log10(abs((double)val) / SHRT_MAX);
}
short db2short(float db)
{
return pow(10, db/20.f) * SHRT_MAX;
}
short short_gain(short val, float db)
{
return (short)(pow(10, db/20.f) * val);
}
float pct2db(float pct)
{
if (pct <= 0) return -72.f;
return 10*log2(pct);
}

View file

@ -67,6 +67,13 @@ void soundstream_fillbuf(struct soundstream *stream, short *buf, int n);
void close_audio_device(int device); void close_audio_device(int device);
int open_device(const char *adriver); int open_device(const char *adriver);
float short2db(short val);
short db2short(float db);
float pct2db(float pct);
short short_gain(short val, float db);
void audio_init(); void audio_init();
#endif #endif