synthio: implement a range compressor with hard knee
This really improves the loudness of the output with multiple notes while being a nice simple algorithm to implement.
This commit is contained in:
parent
9a9f3229fa
commit
c031bda5dd
|
@ -145,20 +145,30 @@ STATIC synthio_envelope_definition_t *synthio_synth_get_note_envelope(synthio_sy
|
|||
}
|
||||
|
||||
|
||||
STATIC uint32_t synthio_synth_sum_envelope(synthio_synth_t *synth) {
|
||||
uint32_t result = 0;
|
||||
for (int chan = 0; chan < CIRCUITPY_SYNTHIO_MAX_CHANNELS; chan++) {
|
||||
mp_obj_t note_obj = synth->span.note_obj[chan];
|
||||
if (note_obj != SYNTHIO_SILENCE) {
|
||||
synthio_envelope_state_t *state = &synth->envelope_state[chan];
|
||||
if (state->state == SYNTHIO_ENVELOPE_STATE_ATTACK) {
|
||||
result += state->level;
|
||||
} else {
|
||||
result += synthio_synth_get_note_envelope(synth, note_obj)->attack_level;
|
||||
#define RANGE_LOW (-28000)
|
||||
#define RANGE_HIGH (28000)
|
||||
#define RANGE_SHIFT (16)
|
||||
#define RANGE_SCALE (0xfffffff / (32768 * CIRCUITPY_SYNTHIO_MAX_CHANNELS - RANGE_HIGH))
|
||||
|
||||
// dynamic range compression via a downward compressor with hard knee
|
||||
//
|
||||
// When the output value is within the range +-28000 (about 85% of full scale),
|
||||
// it is unchanged. Otherwise, it undergoes a gain reduction so that the
|
||||
// largest possible values, (+32768,-32767) * CIRCUITPY_SYNTHIO_MAX_CHANNELS,
|
||||
// still fit within the output range
|
||||
//
|
||||
// This produces a much louder overall volume with multiple voices, without
|
||||
// much additional processing.
|
||||
//
|
||||
// https://en.wikipedia.org/wiki/Dynamic_range_compression
|
||||
STATIC
|
||||
int16_t mix_down_sample(int32_t sample) {
|
||||
if (sample < RANGE_LOW) {
|
||||
sample = (((sample - RANGE_LOW) * RANGE_SCALE) >> RANGE_SHIFT) + RANGE_LOW;
|
||||
} else if (sample > RANGE_HIGH) {
|
||||
sample = (((sample - RANGE_HIGH) * RANGE_SCALE) >> RANGE_SHIFT) + RANGE_HIGH;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return sample;
|
||||
}
|
||||
|
||||
void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t *buffer_length, uint8_t channel) {
|
||||
|
@ -172,27 +182,14 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t
|
|||
synth->buffer_index = !synth->buffer_index;
|
||||
synth->other_channel = 1 - channel;
|
||||
synth->other_buffer_index = synth->buffer_index;
|
||||
int16_t *out_buffer = (int16_t *)(void *)synth->buffers[synth->buffer_index];
|
||||
|
||||
uint16_t dur = MIN(SYNTHIO_MAX_DUR, synth->span.dur);
|
||||
synth->span.dur -= dur;
|
||||
memset(out_buffer, 0, synth->buffer_length);
|
||||
|
||||
int32_t sample_rate = synth->sample_rate;
|
||||
uint32_t total_envelope = synthio_synth_sum_envelope(synth);
|
||||
if (total_envelope < synth->total_envelope) {
|
||||
// total envelope is decreasing. Slowly let remaining notes get louder
|
||||
// the time constant is arbitrary, on the order of 1s at 48kHz
|
||||
total_envelope = synth->total_envelope = (
|
||||
total_envelope + synth->total_envelope * 255) / 256;
|
||||
} else {
|
||||
// total envelope is steady or increasing, so just store this as
|
||||
// the high water mark
|
||||
synth->total_envelope = total_envelope;
|
||||
}
|
||||
if (total_envelope > 0) {
|
||||
uint16_t ovl_loudness = 0x7fffffff / MAX(0x8000, total_envelope);
|
||||
int32_t out_buffer32[dur];
|
||||
|
||||
memset(out_buffer32, 0, sizeof(out_buffer32));
|
||||
for (int chan = 0; chan < CIRCUITPY_SYNTHIO_MAX_CHANNELS; chan++) {
|
||||
mp_obj_t note_obj = synth->span.note_obj[chan];
|
||||
if (note_obj == SYNTHIO_SILENCE) {
|
||||
|
@ -207,7 +204,7 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t
|
|||
}
|
||||
|
||||
// adjust loudness by envelope
|
||||
uint16_t loudness = (ovl_loudness * synth->envelope_state[chan].level) >> 16;
|
||||
uint16_t loudness = synth->envelope_state[chan].level;
|
||||
|
||||
uint32_t dds_rate;
|
||||
const int16_t *waveform = synth->waveform;
|
||||
|
@ -251,10 +248,17 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t
|
|||
accum -= lim;
|
||||
}
|
||||
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
|
||||
out_buffer[i] += (waveform[idx] * loudness) / 65536;
|
||||
out_buffer32[i] += (waveform[idx] * loudness) / 65536;
|
||||
}
|
||||
synth->accum[chan] = accum;
|
||||
}
|
||||
|
||||
int16_t *out_buffer16 = (int16_t *)(void *)synth->buffers[synth->buffer_index];
|
||||
|
||||
// mix down audio
|
||||
for (size_t i = 0; i < dur; i++) {
|
||||
int32_t sample = out_buffer32[i];
|
||||
out_buffer16[i] = mix_down_sample(sample);
|
||||
}
|
||||
|
||||
// advance envelope states
|
||||
|
@ -267,7 +271,7 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t
|
|||
}
|
||||
|
||||
*buffer_length = synth->last_buffer_length = dur * SYNTHIO_BYTES_PER_SAMPLE;
|
||||
*bufptr = (uint8_t *)out_buffer;
|
||||
*bufptr = (uint8_t *)out_buffer16;
|
||||
}
|
||||
|
||||
void synthio_synth_reset_buffer(synthio_synth_t *synth, bool single_channel_output, uint8_t channel) {
|
||||
|
|
|
@ -84,6 +84,25 @@ def synthesize4(synth):
|
|||
yield 36
|
||||
|
||||
|
||||
def synthesize5(synth):
|
||||
notes = [
|
||||
synthio.Note(
|
||||
frequency=synthio.midi_to_hz(60 + i + o),
|
||||
waveform=sine,
|
||||
envelope=envelope,
|
||||
)
|
||||
for i in [0, 4, 7]
|
||||
for o in [0, -12, 12]
|
||||
]
|
||||
|
||||
for n in notes:
|
||||
print(n)
|
||||
synth.press((n,))
|
||||
yield 120
|
||||
synth.release_all()
|
||||
yield 36
|
||||
|
||||
|
||||
def chain(*args):
|
||||
for a in args:
|
||||
yield from a
|
||||
|
@ -94,7 +113,7 @@ with wave.open("tune-noenv.wav", "w") as f:
|
|||
f.setnchannels(1)
|
||||
f.setsampwidth(2)
|
||||
f.setframerate(48000)
|
||||
for n in chain(synthesize2(synth), synthesize3(synth), synthesize4(synth)):
|
||||
for n in chain(synthesize5(synth)):
|
||||
for i in range(n):
|
||||
result, data = audiocore.get_buffer(synth)
|
||||
f.writeframes(data)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
(0, 1, 512, 1)
|
||||
1 [-16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16382, 16382]
|
||||
1 [-16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383]
|
||||
(0, 1, 512, 1)
|
||||
1 [0, 0, 0, 0, 0, 0, 16382, 16382, 16382, 16382, 16382, 16382, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16382, 16382, 16382, 16382, 16382, 16382, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16382, 16382, 16382, 16382, 16382, 16382, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16382, 16382, 16382, 16382, 16382, 16382, 0, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16382, 16382, 16382, 16382, 16382, 16382, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16382, 16382, 16382, 16382, 16382, 16382, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16382, 16382, 16382, 16382, 16382, 16382, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16382, 16382, 16382, 16382, 16382, 16382, 16382, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16382, 16382, 16382, 16382, 16382, 16382, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16382, 16382, 16382, 16382, 16382, 16382, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16382, 16382, 16382, 16382, 16382, 16382, 0, 0]
|
||||
1 [0, 0, 0, 0, 0, 0, 16383, 16383, 16383, 16383, 16383, 16383, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16383, 16383, 16383, 16383, 16383, 16383, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16383, 16383, 16383, 16383, 16383, 16383, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16383, 16383, 16383, 16383, 16383, 16383, 0, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16383, 16383, 16383, 16383, 16383, 16383, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16383, 16383, 16383, 16383, 16383, 16383, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16383, 16383, 16383, 16383, 16383, 16383, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16383, 16383, 16383, 16383, 16383, 16383, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16383, 16383, 16383, 16383, 16383, 16383, 0, 0, 0, 0, 0, 0, -16383, -16383, -16383, -16383, -16383, -16383, 0, 0, 0, 0, 0, 0, 16383, 16383, 16383, 16383, 16383, 16383, 0, 0]
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
()
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
(80,)
|
||||
[-16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383]
|
||||
[-16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383]
|
||||
(80, 91)
|
||||
[0, 0, 16382, 16382, 0, -16382, -16382, 0, 16382, 16382, 0, 0, 16382, 0, 0, -16382, -16382, 0, 16382, 16382, 0, 0, 16382, 0]
|
||||
[0, 0, 28045, 28045, 0, -28046, -28046, 0, 28045, 28045, 0, 0, 28045, 0, 0, -28046, -28046, 0, 28045, 28045, 0, 0, 28045, 0]
|
||||
(91,)
|
||||
[-16382, 0, 0, 16382, 0, 0, 16382, 16382, 0, -16382, -16382, 0, 16382, 16382, 0, 0, 16382, 0, 0, -16382, -16382, -16382, 16382, 16382]
|
||||
(-5242, 5241)
|
||||
(-10484, 10484)
|
||||
(-15727, 15726)
|
||||
(-16383, 16382)
|
||||
(-14286, 14285)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-11009, 11008)
|
||||
(-8912, 8911)
|
||||
(-6815, 6814)
|
||||
(-4718, 4717)
|
||||
(-2621, 2620)
|
||||
(-524, 523)
|
||||
[-28046, 0, 0, 28045, 0, 0, 28045, 28045, 0, -28046, -28046, 0, 28045, 28045, 0, 0, 28045, 0, 0, -28046, -28046, -28046, 28045, 28045]
|
||||
(-5242, 5242)
|
||||
(-10485, 10484)
|
||||
(-15727, 15727)
|
||||
(-16383, 16383)
|
||||
(-14286, 14286)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-11009, 11009)
|
||||
(-8912, 8912)
|
||||
(-6815, 6815)
|
||||
(-4718, 4718)
|
||||
(-2621, 2621)
|
||||
(-524, 524)
|
||||
(0, 0)
|
||||
(0, 0)
|
||||
(0, 0)
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
()
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
(Note(frequency=830.6076004423605, amplitude=1.0, tremolo_rate=0.0, tremolo_depth=0.0, vibrato_rate=0.0, vibrato_depth=0.0, waveform=None, envelope=None),)
|
||||
[-16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383, 16382, 16382, 16382, 16382, 16382, -16383, -16383, -16383, -16383, -16383]
|
||||
[-16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383, 16383, 16383, 16383, 16383, 16383, -16383, -16383, -16383, -16383, -16383]
|
||||
(Note(frequency=830.6076004423605, amplitude=1.0, tremolo_rate=0.0, tremolo_depth=0.0, vibrato_rate=0.0, vibrato_depth=0.0, waveform=None, envelope=None), Note(frequency=830.6076004423605, amplitude=1.0, tremolo_rate=0.0, tremolo_depth=0.0, vibrato_rate=0.0, vibrato_depth=0.0, waveform=None, envelope=None))
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 16382, 0, 0, 0, 0, -16382, 0, 0, 0, 0, 16382, 0, 0, 0, 0, -16382]
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 28045, 0, 0, 0, 0, -28046, 0, 0, 0, 0, 28045, 0, 0, 0, 0, -28046]
|
||||
(Note(frequency=830.6076004423605, amplitude=1.0, tremolo_rate=0.0, tremolo_depth=0.0, vibrato_rate=0.0, vibrato_depth=0.0, waveform=None, envelope=None),)
|
||||
[0, 0, 0, 16382, 0, 0, 0, 0, 0, 0, 0, 0, 16382, 0, 0, 0, 0, -16382, 0, 0, 0, 0, 16382, 0]
|
||||
(-5242, 5241)
|
||||
(-10484, 10484)
|
||||
(-15727, 15726)
|
||||
(-16383, 16382)
|
||||
(-14286, 14285)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-13106, 13105)
|
||||
(-11009, 11008)
|
||||
(-8912, 8911)
|
||||
(-6815, 6814)
|
||||
(-4718, 4717)
|
||||
(-2621, 2620)
|
||||
(-524, 523)
|
||||
[0, 0, 0, 28045, 0, 0, 0, 0, 0, 0, 0, 0, 28045, 0, 0, 0, 0, -28046, 0, 0, 0, 0, 28045, 0]
|
||||
(-5242, 5242)
|
||||
(-10485, 10484)
|
||||
(-15727, 15727)
|
||||
(-16383, 16383)
|
||||
(-14286, 14286)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-13106, 13106)
|
||||
(-11009, 11009)
|
||||
(-8912, 8912)
|
||||
(-6815, 6815)
|
||||
(-4718, 4718)
|
||||
(-2621, 2621)
|
||||
(-524, 524)
|
||||
(0, 0)
|
||||
(0, 0)
|
||||
(0, 0)
|
||||
|
|
Loading…
Reference in New Issue