added oscillators, unison, triangle, rectangle, pulse width, auto connect to jack output, and auto connect alsa input and control unison spread with a midi knob and pulse width with another

master
vampirefrog 6 years ago
parent 525c1d7f09
commit 114b8b15b3

@ -59,37 +59,19 @@ void usage () {
);
}
void
process_silence (jack_nframes_t nframes)
{
void process_silence (jack_nframes_t nframes) {
sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
}
void
process_audio (jack_nframes_t nframes)
{
void process_audio (jack_nframes_t nframes) {
sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
for(int i = 0; i < nframes; i++) {
buffer[i] = synth_render_sample(&synth) / 32767.0;
}
// jack_nframes_t frames_left = nframes;
// while (wave_length - offset < frames_left) {
// memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset));
// frames_left -= wave_length - offset;
// offset = 0;
// }
// if (frames_left > 0) {
// memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left);
// offset += frames_left;
// }
}
int
process (jack_nframes_t nframes, void *arg)
{
int process (jack_nframes_t nframes, void *arg) {
if (transport_aware) {
jack_position_t pos;
@ -149,6 +131,8 @@ snd_seq_t *open_seq() {
fprintf(stderr, "Error creating sequencer port.\n");
exit(1);
}
snd_seq_connect_from(seq_handle, portid, 32, 0);
return(seq_handle);
}
@ -159,14 +143,23 @@ void midi_action(snd_seq_t *seq_handle) {
do {
snd_seq_event_input(seq_handle, &ev);
switch (ev->type) {
case SND_SEQ_EVENT_NOTEON:
printf("Note on %d (%s) %d\n", ev->data.note.note, midi_note_name(ev->data.note.note), ev->data.note.velocity);
synth_note_on(&synth, ev->data.note.note, ev->data.note.velocity);
break;
case SND_SEQ_EVENT_NOTEOFF:
printf("Note off %d\n", ev->data.note.note);
synth_note_off(&synth, ev->data.note.note, ev->data.note.velocity);
break;
case SND_SEQ_EVENT_NOTEON:
printf("Note on %d (%s) %d\n", ev->data.note.note, midi_note_name(ev->data.note.note), ev->data.note.velocity);
synth_note_on(&synth, ev->data.note.note, ev->data.note.velocity);
break;
case SND_SEQ_EVENT_NOTEOFF:
printf("Note off %d\n", ev->data.note.note);
synth_note_off(&synth, ev->data.note.note, ev->data.note.velocity);
break;
case SND_SEQ_EVENT_CONTROLLER:
printf("CC %d %d\n", ev->data.control.param, ev->data.control.value);
if(ev->data.control.param == 93) {
synth_set_pulse_width(&synth, ev->data.control.value);
}
if(ev->data.control.param == 74) {
synth_set_unison_spread(&synth, ev->data.control.value);
}
break;
}
snd_seq_free_event(ev);
} while (snd_seq_event_input_pending(seq_handle, 0) > 0);
@ -176,14 +169,10 @@ void midi_action(snd_seq_t *seq_handle) {
int main(int argc, char **argv) {
sample_t scale;
int i, attack_length, decay_length;
double *amp;
double max_amp = 0.5;
int option_index;
int opt;
int got_bpm = 0;
int attack_percent = 1, decay_percent = 10, dur_arg = 100;
char *client_name = 0;
char *bpm_string = "bpm";
char *bpm_string = "synth out";
int verbose = 0;
jack_status_t status;
@ -219,25 +208,38 @@ int main(int argc, char **argv) {
/* Initial Jack setup, get sample rate */
if (!client_name) {
client_name = (char *) malloc (9 * sizeof (char));
strcpy (client_name, "metro");
client_name = strdup("vampi va");
}
if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) {
fprintf (stderr, "jack server not running?\n");
return 1;
}
jack_set_process_callback (client, process, 0);
output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
jack_set_process_callback(client, process, 0);
output_port = jack_port_register(client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
sr = jack_get_sample_rate (client);
sr = jack_get_sample_rate(client);
synth_init(&synth);
synth.attack = 50;
synth.decay = 200;
synth.sustain = 60;
synth.release = 100;
if (jack_activate (client)) {
fprintf (stderr, "cannot activate client");
exit (1);
}
const char **ports;
ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
if (ports == NULL) {
fprintf(stderr, "no physical capture ports\n");
exit (1);
}
/* setup wave table parameters */
if (jack_connect (client, jack_port_name (output_port), ports[0])) {
fprintf (stderr, "cannot connect input ports\n");
}
synth_init(&synth);
synth.attack = 200;
synth.decay = 100;
synth.sustain = 80;
synth.release = 50;
if (jack_activate (client)) {
fprintf (stderr, "cannot activate client");
@ -253,7 +255,6 @@ int main(int argc, char **argv) {
pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
snd_seq_poll_descriptors(seq_handle, pfd, npfd, POLLIN);
while (1) {
printf("poll\n");
if (poll(pfd, npfd, 100000) > 0) {
midi_action(seq_handle);
}

@ -1,28 +1,34 @@
#include <stdio.h>
#include <math.h>
#include "synth.h"
#include "config.h"
#include "tables.inc"
// convert from 16.16 frequency to 16.16 period in samples
static fixed freq2period(fixed freq) {
uint64_t tmp = (uint64_t)SAMPLE_RATE << 32;
return tmp / freq;
}
void synth_init(struct Synth *synth) {
}
uint8_t midi_notes[128];
void synth_note_on(struct Synth *synth, uint8_t note, uint8_t velocity) {
printf("synth_note_on note=%d velocity=%d\n", note, velocity);
// find the first available voice, if any
for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
struct Voice *voice = synth->voices + i;
if(voice->env_state == None) {
voice->phase = voice->time = 0;
voice->freq = (uint32_t)(midi_note_freq_table[note & 0x7f] * 256);
printf("starting voice %d\n", i);
midi_notes[note & 0x7f] = i;
voice->attack = synth->attack;
voice->decay = synth->decay;
voice->sustain = synth->sustain;
voice->release = synth->release;
voice->volume = velocity;
voice->env_state = Attack;
printf("Attack %d\n", synth->attack);
voice_note_start(voice, note, velocity);
break;
}
}
@ -30,71 +36,128 @@ void synth_note_on(struct Synth *synth, uint8_t note, uint8_t velocity) {
void synth_note_off(struct Synth *synth, uint8_t note, uint8_t velocity) {
(void)velocity;
printf("synth_note_off note=%d velocity=%d\n", note, velocity);
printf("stopping voice %d\n", note & 0x7f);
struct Voice *voice = synth->voices + midi_notes[note & 0x7f];
voice->time = 0;
voice->env_state = Release;
printf("Release %d\n", voice->release);
voice_stop(voice);
}
static uint8_t alt = 0;
int16_t synth_render_sample(struct Synth *synth) {
int32_t smpl = 0;
for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
struct Voice *v = synth->voices + i;
if(v->env_state != None) {
v->time++;
int32_t amplitude = 0; // calculate based on velocity and envelope
uint32_t ms_time = v->time * 1000 / SAMPLE_RATE;
switch(v->env_state) {
case Attack:
if(v->attack > 0)
amplitude = v->volume * ms_time / v->attack;
if(ms_time > v->attack) {
printf("Decay %d\n", v->decay);
v->env_state = Decay;
v->time = 0;
}
break;
case Decay:
if(v->decay > 0)
amplitude = (100 * v->volume * (v->decay - ms_time) + v->sustain * v->volume * ms_time) / v->decay / 100;
if(ms_time > v->decay) {
printf("Sustain %d\n", v->sustain);
v->env_state = Sustain;
v->time = 0;
}
break;
case Sustain:
amplitude = v->volume * v->sustain / 100;
break;
case Release:
amplitude = v->volume * (v->release - ms_time) * v->sustain / v->release / 100;
if(ms_time > v->release) {
v->time = 0;
v->freq = 0;
v->env_state = None;
printf("None\n");
}
break;
}
smpl += voice_render_sample(v);
if(smpl > 32767) smpl = 32767;
if(smpl < -32768) smpl = -32768;
}
alt = (alt+1)&1;
return smpl & 0xffff;
}
if(v->env_state != None && v->freq) {
v->phase += (1 << 8);
uint32_t freq_phase = (SAMPLE_RATE << 16) / v->freq;
while(v->phase >= freq_phase)
v->phase -= freq_phase;
int sine_phase = 256 * v->phase / freq_phase;
int sine_phase_next = (sine_phase + 1) & 0xff;
int sine_remainder = v->phase % freq_phase;
// if(v->env_state == Release) {
// printf("amplitude %d volume=%d time=%d ms_time=%d v->release=%d v->sustain=%d\n", amplitude, v->volume, v->time, ms_time, v->release, v->sustain);
// }
smpl += amplitude * sine_table_256[sine_phase] / 255;
}
if(smpl > 32767) smpl = 32767;
if(smpl < -32768) smpl = -32768;
void synth_set_pulse_width(struct Synth *synth, uint8_t w) {
for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
for(int j = 0; j < 7; j++)
synth->voices[i].osc[j].pulse_width = w;
}
}
void synth_set_unison_spread(struct Synth *synth, uint8_t w) {
for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
for(int j = 0; j < 7; j++)
synth->voices[i].unison_spread = w;
}
}
int16_t oscillator_render_sample(struct Oscillator *osc) {
osc->phase += 0x10000; // add one sample in fixed
if(osc->period > 0) // avoid a infinite loop below
while(osc->phase > osc->period)
osc->phase -= osc->period;
uint32_t edge = osc->pulse_width * osc->period / 127;
if(osc->type == Rectangle) {
if(osc->phase >= edge)
return -20000;
else
return 20000;
} else if(osc->type == Triangle) {
if(osc->phase <= edge) {
return ((((osc->phase >> 3) << 6) / (edge >> 3)) << 6) - (1 << 11);
} else {
return (((((osc->period - osc->phase) >> 3) << 6) / ((osc->period - edge) >> 3)) << 6) - (1 << 11);
}
}
return smpl & 0xffff;
}
int16_t voice_render_sample(struct Voice *v) {
if(v->env_state == None)
return 0;
int32_t amplitude = 0; // calculate based on velocity and envelope
uint32_t ms_time = v->time * 1000 / SAMPLE_RATE;
switch(v->env_state) {
case Attack:
if(v->attack > 0)
amplitude = v->volume * ms_time / v->attack;
if(ms_time > v->attack) {
v->env_state = Decay;
v->time = 0;
}
break;
case Decay:
if(v->decay > 0)
amplitude = (100 * v->volume * (v->decay - ms_time) + v->sustain * v->volume * ms_time) / v->decay / 100;
if(ms_time > v->decay) {
v->env_state = Sustain;
v->time = 0;
}
break;
case Sustain:
amplitude = v->volume * v->sustain / 100;
break;
case Release:
if(v->release > 0)
amplitude = v->volume * (v->release - ms_time) * v->sustain / v->release / 100;
if(ms_time > v->release) {
v->time = 0;
v->env_state = None;
}
break;
}
v->time++;
if(v->env_state != None) {
int32_t ret = 0;
for(int i = 0; i < 7; i++) ret += oscillator_render_sample(&v->osc[i]);
return amplitude * ret / 32767;
}
}
void voice_note_start(struct Voice *voice, uint8_t note, uint8_t velocity) {
voice->time = 0;
voice->volume = velocity * 128;
voice->env_state = Attack;
note &= 0x7f;
voice->osc[0].type = Triangle;
voice->osc[0].freq = midi_note_freq_fixed[note];
int freq_below = voice->osc[0].freq - midi_note_freq_fixed[note - 1];
int freq_above = midi_note_freq_fixed[note + 1] - voice->osc[0].freq;
voice->osc[0].period = freq2period(voice->osc[0].freq);
for(int i = 1; i <= 3; i++) {
voice->osc[i].type = voice->osc[0].type;
voice->osc[i].freq = voice->osc[0].freq - voice->unison_spread * freq_below * i / 3 / 127;
voice->osc[i].period = freq2period(voice->osc[i].freq);
}
for(int i = 4; i < 7; i++) {
voice->osc[i].type = voice->osc[0].type;
voice->osc[i].freq = voice->osc[0].freq + voice->unison_spread * freq_above * (i - 3) / 3 / 127;
voice->osc[i].period = freq2period(voice->osc[i].freq);
}
}
void voice_stop(struct Voice *voice) {
voice->time = 0;
voice->env_state = Release;
}

@ -6,11 +6,44 @@
#define SYNTH_NUM_VOICES 64
#define TUNING 440
typedef uint32_t fixed;
struct Oscillator {
fixed phase; // fixed 16.16
fixed freq; // fixed 16.16
fixed period; // period in samples, fixed 16.16
enum {
Rectangle,
Triangle
} type;
uint8_t pulse_width; // 0 - 127
};
int16_t oscillator_render_sample(struct Oscillator *osc);
void oscillator_set_freq(fixed freq); // fixed 16.16
struct Sampler {
fixed phase; // fixed 16.16
fixed freq; // fixed 16.16
fixed period; // period in samples, fixed 16.16
uint32_t length;
uint16_t length_log2; // length = 1 << length_log2;
int16_t *data;
enum {
Nearest,
Linear
} interpolation;
};
int16_t sampler_sample(struct Sampler *sampler);
void sampler_set_freq(fixed freq);
struct Voice {
uint32_t phase;
uint32_t time;
uint16_t volume;
uint32_t freq;
// Envelope
enum {
@ -23,8 +56,16 @@ struct Voice {
uint16_t attack, decay, release; // in ms
uint16_t sustain; // percentage
uint8_t unison_spread;
struct Oscillator osc[7];
};
struct Synth;
void voice_note_start(struct Voice *voice, uint8_t note, uint8_t velocity);
void voice_stop(struct Voice *voice);
int16_t voice_render_sample(struct Voice *voice);
struct Synth {
struct Voice voices[SYNTH_NUM_VOICES];
uint16_t attack, decay, sustain, release; // in ms
@ -34,5 +75,7 @@ void synth_init(struct Synth *synth);
void synth_note_on(struct Synth *synth, uint8_t note, uint8_t velocity);
void synth_note_off(struct Synth *synth, uint8_t note, uint8_t velocity);
int16_t synth_render_sample(struct Synth *synth);
void synth_set_pulse_width(struct Synth *s, uint8_t w);
void synth_set_unison_spread(struct Synth *s, uint8_t w);
#endif /* SYNTH_H_ */

@ -258,132 +258,263 @@ static const int16_t sine_table_256[256] = {
// http://www.richardbrice.net/midi_notes.htm
static const float midi_note_freq_table[128] = {
8.176,
8.662,
9.177,
9.723,
10.301,
10.913,
11.562,
12.250,
12.978,
13.750,
14.568,
15.434,
16.352,
17.324,
18.354,
19.445,
20.601,
21.826,
23.124,
24.499,
25.956,
27.500, // Lowest note on piano
29.135,
30.867,
32.703,
34.648,
36.708,
38.890,
41.203,
43.653,
46.249,
48.999,
51.913,
55.000,
58.270,
61.735,
65.406,
69.295,
73.416,
77.781,
82.406,
87.307,
92.499,
97.998,
103.82,
110.00,
116.54,
123.47,
130.81,
138.59,
146.83,
155.56,
164.81,
174.61,
184.99,
195.99,
207.65,
220.00,
233.08,
246.94,
261.63, // Middle-C
277.18,
293.66,
311.13,
329.63,
349.23,
369.99,
391.99,
415.31,
440.00,
466.16,
489.88,
523.25,
554.37,
587.33,
622.25,
659.26,
698.46,
739.99,
783.99,
830.61,
880.00,
932.32,
987.77,
1046.5,
1108.7,
1174.7,
1244.5,
1318.5,
1396.9,
1480.0,
1568.0,
1661.2,
1760.0,
1864.7,
1975.5,
2093.0,
2217.5,
2349.3,
2489.0,
2637.0,
2793.8,
2960.0,
3136.0,
3322.4,
3520.0,
3729.3,
3951.1,
4186.0, // Highest note on piano
4434.9,
4698.6,
4978.0,
5274.0,
5587.7,
5919.9,
6271.9,
6644.9,
7040.0,
7458.6,
7902.1,
8372.0,
8869.8,
9397.3,
9956.1,
10548.1,
11175.3,
11839.8,
12543.9,
8.1757989156,
8.661957218,
9.1770239974,
9.7227182413,
10.3008611535,
10.9133822323,
11.5623257097,
12.2498573744,
12.9782717994,
13.75,
14.5676175474,
15.4338531643,
16.3515978313,
17.3239144361,
18.3540479948,
19.4454364826,
20.6017223071,
21.8267644646,
23.1246514195,
24.4997147489,
25.9565435987,
27.5,
29.1352350949,
30.8677063285,
32.7031956626,
34.6478288721,
36.7080959897,
38.8908729653,
41.2034446141,
43.6535289291,
46.249302839,
48.9994294977,
51.9130871975,
55,
58.2704701898,
61.735412657,
65.4063913251,
69.2956577442,
73.4161919794,
77.7817459305,
82.4068892282,
87.3070578583,
92.4986056779,
97.9988589954,
103.826174395,
110,
116.5409403795,
123.470825314,
130.8127826503,
138.5913154884,
146.8323839587,
155.563491861,
164.8137784564,
174.6141157165,
184.9972113558,
195.9977179909,
207.65234879,
220,
233.081880759,
246.9416506281,
261.6255653006,
277.1826309769,
293.6647679174,
311.1269837221,
329.6275569129,
349.228231433,
369.9944227116,
391.9954359818,
415.3046975799,
440,
466.1637615181,
493.8833012561,
523.2511306012,
554.3652619537,
587.3295358348,
622.2539674442,
659.2551138257,
698.456462866,
739.9888454233,
783.9908719635,
830.6093951599,
880,
932.3275230362,
987.7666025122,
1046.5022612024,
1108.7305239075,
1174.6590716696,
1244.5079348883,
1318.5102276515,
1396.912925732,
1479.9776908465,
1567.981743927,
1661.2187903198,
1760,
1864.6550460724,
1975.5332050245,
2093.0045224048,
2217.461047815,
2349.3181433393,
2489.0158697767,
2637.020455303,
2793.825851464,
2959.9553816931,
3135.963487854,
3322.4375806396,
3520,
3729.3100921447,
3951.066410049,
4186.0090448096,
4434.92209563,
4698.6362866785,
4978.0317395533,
5274.0409106059,
5587.6517029281,
5919.9107633862,
6271.926975708,
6644.8751612791,
7040,
7458.6201842894,
7902.132820098,
8372.0180896192,
8869.8441912599,
9397.2725733571,
9956.0634791066,
10548.0818212118,
11175.3034058561,
11839.8215267723,
12543.853951416,
};
static const uint32_t midi_note_freq_fixed[128] = {
535809,
567670,
601425,
637188,
675077,
715219,
757749,
802807,
850544,
901120,
954703,
1011473,
1071618,
1135340,
1202851,
1274376,
1350154,
1430439,
1515497,
1605613,
1701088,
1802240,
1909407,
2022946,
2143237,
2270680,
2405702,
2548752,
2700309,
2860878,
3030994,
3211227,
3402176,
3604480,
3818814,
4045892,
4286473,
4541360,
4811404,
5097505,
5400618,
5721755,
6061989,
6422453,
6804352,
7208960,
7637627,
8091784,
8572947,
9082720,
9622807,
10195009,
10801236,
11443511,
12123977,
12844906,
13608704,
14417920,
15275254,
16183568,
17145893,
18165441,
19245614,
20390018,
21602472,
22887021,
24247954,
25689813,
27217409,
28835840,
30550508,
32367136,
34291786,
36330882,
38491228,
40780036,
43204943,
45774043,
48495909,
51379626,
54434817,
57671680,
61101017,
64734272,
68583572,
72661764,
76982457,
81560072,
86409886,
91548086,
96991818,
102759252,
108869635,
115343360,
122202033,
129468544,
137167144,
145323527,
153964914,
163120144,
172819773,
183096171,
193983636,
205518503,
217739269,
230686720,
244404066,
258937088,
274334289,
290647054,
307929828,
326240288,
345639545,
366192342,
387967272,
411037006,
435478539,
461373440,
488808132,
517874176,
548668578,
581294109,
615859655,
652480576,
691279090,
732384684,
775934544,
822074013,
};

Loading…
Cancel
Save