Browse Source

initial commit

vampirefrog 3 years ago
commit
525c1d7f09
5 changed files with 789 additions and 0 deletions
  1. 1
    0
      config.h
  2. 261
    0
      main.c
  3. 100
    0
      synth.c
  4. 38
    0
      synth.h
  5. 389
    0
      tables.inc

+ 1
- 0
config.h View File

@@ -0,0 +1 @@
1
+#define SAMPLE_RATE 48000

+ 261
- 0
main.c View File

@@ -0,0 +1,261 @@
1
+/*
2
+		Copyright (C) 2002 Anthony Van Groningen
3
+
4
+		This program is free software; you can redistribute it and/or modify
5
+		it under the terms of the GNU General Public License as published by
6
+		the Free Software Foundation; either version 2 of the License, or
7
+		(at your option) any later version.
8
+		This program is distributed in the hope that it will be useful,
9
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+		GNU General Public License for more details.
12
+		You should have received a copy of the GNU General Public License
13
+		along with this program; if not, write to the Free Software
14
+		Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15
+*/
16
+
17
+#include <stdlib.h>
18
+#include <stdio.h>
19
+#include <errno.h>
20
+#include <unistd.h>
21
+#include <math.h>
22
+#include <getopt.h>
23
+#include <string.h>
24
+
25
+#include <jack/jack.h>
26
+#include <jack/transport.h>
27
+
28
+#include <asoundlib.h>
29
+
30
+#include "synth.h"
31
+struct Synth synth;
32
+
33
+typedef jack_default_audio_sample_t sample_t;
34
+
35
+const double PI = 3.14;
36
+
37
+jack_client_t *client;
38
+jack_port_t *output_port;
39
+unsigned long sr;
40
+int freq = 880;
41
+int bpm;
42
+jack_nframes_t tone_length, wave_length;
43
+sample_t *wave;
44
+long offset = 0;
45
+int transport_aware = 0;
46
+jack_transport_state_t transport_state;
47
+
48
+void usage () {
49
+	fprintf (stderr, "\n"
50
+"usage: jack_metro \n"
51
+"              [ --frequency OR -f frequency (in Hz) ]\n"
52
+"              [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n"
53
+"              [ --duration OR -D duration (in ms) ]\n"
54
+"              [ --attack OR -a attack (in percent of duration) ]\n"
55
+"              [ --decay OR -d decay (in percent of duration) ]\n"
56
+"              [ --name OR -n jack name for metronome client ]\n"
57
+"              [ --transport OR -t transport aware ]\n"
58
+"              --bpm OR -b beats per minute\n"
59
+);
60
+}
61
+
62
+void
63
+process_silence (jack_nframes_t nframes)
64
+{
65
+	sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
66
+	memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
67
+}
68
+
69
+void
70
+process_audio (jack_nframes_t nframes)
71
+{
72
+
73
+	sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
74
+	for(int i = 0; i < nframes; i++) {
75
+		buffer[i] = synth_render_sample(&synth) / 32767.0;
76
+	}
77
+	// jack_nframes_t frames_left = nframes;
78
+
79
+	// while (wave_length - offset < frames_left) {
80
+	// 	memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset));
81
+	// 	frames_left -= wave_length - offset;
82
+	// 	offset = 0;
83
+	// }
84
+	// if (frames_left > 0) {
85
+	// 	memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left);
86
+	// 	offset += frames_left;
87
+	// }
88
+}
89
+
90
+int
91
+process (jack_nframes_t nframes, void *arg)
92
+{
93
+	if (transport_aware) {
94
+		jack_position_t pos;
95
+
96
+		if (jack_transport_query (client, &pos)
97
+				!= JackTransportRolling) {
98
+
99
+			process_silence (nframes);
100
+			return 0;
101
+		}
102
+		offset = pos.frame % wave_length;
103
+	}
104
+	process_audio (nframes);
105
+	return 0;
106
+}
107
+
108
+int
109
+sample_rate_change () {
110
+	printf("Sample rate has changed! Exiting...\n");
111
+	exit(-1);
112
+}
113
+
114
+static char *midi_note_names[12] = {
115
+	"C",
116
+	"C#",
117
+	"D",
118
+	"D#",
119
+	"E",
120
+	"F",
121
+	"F#",
122
+	"G",
123
+	"G#",
124
+	"A",
125
+	"A#",
126
+	"B",
127
+};
128
+
129
+const char *midi_note_name(int note) {
130
+	return midi_note_names[note % 12];
131
+}
132
+
133
+snd_seq_t *open_seq();
134
+void midi_action(snd_seq_t *seq_handle);
135
+
136
+snd_seq_t *open_seq() {
137
+
138
+	snd_seq_t *seq_handle;
139
+	int portid;
140
+
141
+	if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, 0) < 0) {
142
+		fprintf(stderr, "Error opening ALSA sequencer.\n");
143
+		exit(1);
144
+	}
145
+	snd_seq_set_client_name(seq_handle, "Vampi Synth");
146
+	if ((portid = snd_seq_create_simple_port(seq_handle, "Cornhole",
147
+						SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
148
+						SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
149
+		fprintf(stderr, "Error creating sequencer port.\n");
150
+		exit(1);
151
+	}
152
+	return(seq_handle);
153
+}
154
+
155
+void midi_action(snd_seq_t *seq_handle) {
156
+
157
+	snd_seq_event_t *ev;
158
+
159
+	do {
160
+		snd_seq_event_input(seq_handle, &ev);
161
+		switch (ev->type) {
162
+		case SND_SEQ_EVENT_NOTEON:
163
+			printf("Note on %d (%s) %d\n", ev->data.note.note, midi_note_name(ev->data.note.note), ev->data.note.velocity);
164
+			synth_note_on(&synth, ev->data.note.note, ev->data.note.velocity);
165
+			break;
166
+		case SND_SEQ_EVENT_NOTEOFF:
167
+			printf("Note off %d\n", ev->data.note.note);
168
+			synth_note_off(&synth, ev->data.note.note, ev->data.note.velocity);
169
+			break;
170
+		}
171
+		snd_seq_free_event(ev);
172
+	} while (snd_seq_event_input_pending(seq_handle, 0) > 0);
173
+}
174
+
175
+
176
+int main(int argc, char **argv) {
177
+	sample_t scale;
178
+	int i, attack_length, decay_length;
179
+	double *amp;
180
+	double max_amp = 0.5;
181
+	int option_index;
182
+	int opt;
183
+	int got_bpm = 0;
184
+	int attack_percent = 1, decay_percent = 10, dur_arg = 100;
185
+	char *client_name = 0;
186
+	char *bpm_string = "bpm";
187
+	int verbose = 0;
188
+	jack_status_t status;
189
+
190
+	const char *options = "f:A:D:a:d:b:n:thv";
191
+	struct option long_options[] =
192
+	{
193
+		{"name", 1, 0, 'n'},
194
+		{"transport", 0, 0, 't'},
195
+		{"help", 0, 0, 'h'},
196
+		{"verbose", 0, 0, 'v'},
197
+		{0, 0, 0, 0}
198
+	};
199
+
200
+	while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) {
201
+		switch (opt) {
202
+		case 'n':
203
+			client_name = (char *) malloc (strlen (optarg) * sizeof (char));
204
+			strcpy (client_name, optarg);
205
+			break;
206
+		case 't':
207
+			transport_aware = 1;
208
+			break;
209
+		default:
210
+			fprintf (stderr, "unknown option %c\n", opt);
211
+		case 'h':
212
+			usage ();
213
+			return -1;
214
+		case 'v':
215
+			verbose = 1;
216
+			break;
217
+		}
218
+	}
219
+
220
+	/* Initial Jack setup, get sample rate */
221
+	if (!client_name) {
222
+		client_name = (char *) malloc (9 * sizeof (char));
223
+		strcpy (client_name, "metro");
224
+	}
225
+	if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) {
226
+		fprintf (stderr, "jack server not running?\n");
227
+		return 1;
228
+	}
229
+	jack_set_process_callback (client, process, 0);
230
+	output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
231
+
232
+	sr = jack_get_sample_rate (client);
233
+
234
+	synth_init(&synth);
235
+	synth.attack = 50;
236
+	synth.decay = 200;
237
+	synth.sustain = 60;
238
+	synth.release = 100;
239
+
240
+	/* setup wave table parameters */
241
+
242
+	if (jack_activate (client)) {
243
+		fprintf (stderr, "cannot activate client");
244
+		return 1;
245
+	}
246
+
247
+	snd_seq_t *seq_handle;
248
+	int npfd;
249
+	struct pollfd *pfd;
250
+
251
+	seq_handle = open_seq();
252
+	npfd = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
253
+	pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
254
+	snd_seq_poll_descriptors(seq_handle, pfd, npfd, POLLIN);
255
+	while (1) {
256
+		printf("poll\n");
257
+		if (poll(pfd, npfd, 100000) > 0) {
258
+			midi_action(seq_handle);
259
+		}
260
+	}
261
+}

+ 100
- 0
synth.c View File

@@ -0,0 +1,100 @@
1
+#include <stdio.h>
2
+
3
+#include "synth.h"
4
+#include "config.h"
5
+
6
+#include "tables.inc"
7
+
8
+void synth_init(struct Synth *synth) {
9
+}
10
+
11
+uint8_t midi_notes[128];
12
+void synth_note_on(struct Synth *synth, uint8_t note, uint8_t velocity) {
13
+	for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
14
+		struct Voice *voice = synth->voices + i;
15
+		if(voice->env_state == None) {
16
+			voice->phase = voice->time = 0;
17
+			voice->freq = (uint32_t)(midi_note_freq_table[note & 0x7f] * 256);
18
+			midi_notes[note & 0x7f] = i;
19
+			voice->attack = synth->attack;
20
+			voice->decay = synth->decay;
21
+			voice->sustain = synth->sustain;
22
+			voice->release = synth->release;
23
+			voice->volume = velocity;
24
+			voice->env_state = Attack;
25
+			printf("Attack %d\n", synth->attack);
26
+			break;
27
+		}
28
+	}
29
+}
30
+
31
+void synth_note_off(struct Synth *synth, uint8_t note, uint8_t velocity) {
32
+	(void)velocity;
33
+	struct Voice *voice = synth->voices + midi_notes[note & 0x7f];
34
+	voice->time = 0;
35
+	voice->env_state = Release;
36
+	printf("Release %d\n", voice->release);
37
+}
38
+
39
+int16_t synth_render_sample(struct Synth *synth) {
40
+	int32_t smpl = 0;
41
+	for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
42
+		struct Voice *v = synth->voices + i;
43
+		if(v->env_state != None) {
44
+
45
+			v->time++;
46
+
47
+			int32_t amplitude = 0; // calculate based on velocity and envelope
48
+			uint32_t ms_time = v->time * 1000 / SAMPLE_RATE;
49
+			switch(v->env_state) {
50
+				case Attack:
51
+					if(v->attack > 0)
52
+						amplitude = v->volume * ms_time / v->attack;
53
+					if(ms_time > v->attack) {
54
+						printf("Decay %d\n", v->decay);
55
+						v->env_state = Decay;
56
+						v->time = 0;
57
+					}
58
+					break;
59
+				case Decay:
60
+					if(v->decay > 0)
61
+						amplitude = (100 * v->volume * (v->decay - ms_time) + v->sustain * v->volume * ms_time) / v->decay / 100;
62
+					if(ms_time > v->decay) {
63
+						printf("Sustain %d\n", v->sustain);
64
+						v->env_state = Sustain;
65
+						v->time = 0;
66
+					}
67
+					break;
68
+				case Sustain:
69
+					amplitude = v->volume * v->sustain / 100;
70
+					break;
71
+				case Release:
72
+					amplitude = v->volume * (v->release - ms_time) * v->sustain / v->release / 100;
73
+					if(ms_time > v->release) {
74
+						v->time = 0;
75
+						v->freq = 0;
76
+						v->env_state = None;
77
+						printf("None\n");
78
+					}
79
+					break;
80
+			}
81
+
82
+			if(v->env_state != None && v->freq) {
83
+				v->phase += (1 << 8);
84
+				uint32_t freq_phase = (SAMPLE_RATE << 16) / v->freq;
85
+				while(v->phase >= freq_phase)
86
+					v->phase -= freq_phase;
87
+				int sine_phase = 256 * v->phase / freq_phase;
88
+				int sine_phase_next = (sine_phase + 1) & 0xff;
89
+				int sine_remainder = v->phase % freq_phase;
90
+				// if(v->env_state == Release) {
91
+				// 	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);
92
+				// }
93
+				smpl += amplitude * sine_table_256[sine_phase] / 255;
94
+			}
95
+			if(smpl > 32767) smpl = 32767;
96
+			if(smpl < -32768) smpl = -32768;
97
+		}
98
+	}
99
+	return smpl & 0xffff;
100
+}

+ 38
- 0
synth.h View File

@@ -0,0 +1,38 @@
1
+#ifndef SYNTH_H_
2
+#define SYNTH_H_
3
+
4
+#include <stdint.h>
5
+
6
+#define SYNTH_NUM_VOICES 64
7
+#define TUNING 440
8
+
9
+struct Voice {
10
+	uint32_t phase;
11
+	uint32_t time;
12
+	uint16_t volume;
13
+	uint32_t freq;
14
+
15
+	// Envelope
16
+	enum {
17
+		None,
18
+		Attack,
19
+		Decay,
20
+		Sustain,
21
+		Release
22
+	} env_state;
23
+
24
+	uint16_t attack, decay, release; // in ms
25
+	uint16_t sustain; // percentage
26
+};
27
+
28
+struct Synth {
29
+	struct Voice voices[SYNTH_NUM_VOICES];
30
+	uint16_t attack, decay, sustain, release; // in ms
31
+};
32
+
33
+void synth_init(struct Synth *synth);
34
+void synth_note_on(struct Synth *synth, uint8_t note, uint8_t velocity);
35
+void synth_note_off(struct Synth *synth, uint8_t note, uint8_t velocity);
36
+int16_t synth_render_sample(struct Synth *synth);
37
+
38
+#endif /* SYNTH_H_ */

+ 389
- 0
tables.inc View File

@@ -0,0 +1,389 @@
1
+static const int16_t sine_table_256[256] = {
2
+	0,
3
+	402,
4
+	804,
5
+	1205,
6
+	1606,
7
+	2005,
8
+	2404,
9
+	2801,
10
+	3196,
11
+	3590,
12
+	3981,
13
+	4370,
14
+	4756,
15
+	5139,
16
+	5519,
17
+	5896,
18
+	6270,
19
+	6639,
20
+	7005,
21
+	7366,
22
+	7723,
23
+	8075,
24
+	8423,
25
+	8765,
26
+	9102,
27
+	9433,
28
+	9759,
29
+	10079,
30
+	10393,
31
+	10701,
32
+	11002,
33
+	11297,
34
+	11585,
35
+	11865,
36
+	12139,
37
+	12405,
38
+	12664,
39
+	12915,
40
+	13159,
41
+	13394,
42
+	13622,
43
+	13841,
44
+	14052,
45
+	14255,
46
+	14449,
47
+	14634,
48
+	14810,
49
+	14977,
50
+	15136,
51
+	15285,
52
+	15425,
53
+	15556,
54
+	15678,
55
+	15790,
56
+	15892,
57
+	15985,
58
+	16068,
59
+	16142,
60
+	16206,
61
+	16260,
62
+	16304,
63
+	16339,
64
+	16363,
65
+	16378,
66
+	16383,
67
+	16378,
68
+	16363,
69
+	16339,
70
+	16304,
71
+	16260,
72
+	16206,
73
+	16142,
74
+	16068,
75
+	15985,
76
+	15892,
77
+	15790,
78
+	15678,
79
+	15556,
80
+	15425,
81
+	15285,
82
+	15136,
83
+	14977,
84
+	14810,
85
+	14634,
86
+	14449,
87
+	14255,
88
+	14052,
89
+	13841,
90
+	13622,
91
+	13394,
92
+	13159,
93
+	12915,
94
+	12664,
95
+	12405,
96
+	12139,
97
+	11865,
98
+	11585,
99
+	11297,
100
+	11002,
101
+	10701,
102
+	10393,
103
+	10079,
104
+	9759,
105
+	9433,
106
+	9102,
107
+	8765,
108
+	8423,
109
+	8075,
110
+	7723,
111
+	7366,
112
+	7005,
113
+	6639,
114
+	6270,
115
+	5896,
116
+	5519,
117
+	5139,
118
+	4756,
119
+	4370,
120
+	3981,
121
+	3590,
122
+	3196,
123
+	2801,
124
+	2404,
125
+	2005,
126
+	1606,
127
+	1205,
128
+	804,
129
+	402,
130
+	0,
131
+	-402,
132
+	-804,
133
+	-1205,
134
+	-1606,
135
+	-2005,
136
+	-2404,
137
+	-2801,
138
+	-3196,
139
+	-3590,
140
+	-3981,
141
+	-4370,
142
+	-4756,
143
+	-5139,
144
+	-5519,
145
+	-5896,
146
+	-6270,
147
+	-6639,
148
+	-7005,
149
+	-7366,
150
+	-7723,
151
+	-8075,
152
+	-8423,
153
+	-8765,
154
+	-9102,
155
+	-9433,
156
+	-9759,
157
+	-10079,
158
+	-10393,
159
+	-10701,
160
+	-11002,
161
+	-11297,
162
+	-11585,
163
+	-11865,
164
+	-12139,
165
+	-12405,
166
+	-12664,
167
+	-12915,
168
+	-13159,
169
+	-13394,
170
+	-13622,
171
+	-13841,
172
+	-14052,
173
+	-14255,
174
+	-14449,
175
+	-14634,
176
+	-14810,
177
+	-14977,
178
+	-15136,
179
+	-15285,
180
+	-15425,
181
+	-15556,
182
+	-15678,
183
+	-15790,
184
+	-15892,
185
+	-15985,
186
+	-16068,
187
+	-16142,
188
+	-16206,
189
+	-16260,
190
+	-16304,
191
+	-16339,
192
+	-16363,
193
+	-16378,
194
+	-16383,
195
+	-16378,
196
+	-16363,
197
+	-16339,
198
+	-16304,
199
+	-16260,
200
+	-16206,
201
+	-16142,
202
+	-16068,
203
+	-15985,
204
+	-15892,
205
+	-15790,
206
+	-15678,
207
+	-15556,
208
+	-15425,
209
+	-15285,
210
+	-15136,
211
+	-14977,
212
+	-14810,
213
+	-14634,
214
+	-14449,
215
+	-14255,
216
+	-14052,
217
+	-13841,
218
+	-13622,
219
+	-13394,
220
+	-13159,
221
+	-12915,
222
+	-12664,
223
+	-12405,
224
+	-12139,
225
+	-11865,
226
+	-11585,
227
+	-11297,
228
+	-11002,
229
+	-10701,
230
+	-10393,
231
+	-10079,
232
+	-9759,
233
+	-9433,
234
+	-9102,
235
+	-8765,
236
+	-8423,
237
+	-8075,
238
+	-7723,
239
+	-7366,
240
+	-7005,
241
+	-6639,
242
+	-6270,
243
+	-5896,
244
+	-5519,
245
+	-5139,
246
+	-4756,
247
+	-4370,
248
+	-3981,
249
+	-3590,
250
+	-3196,
251
+	-2801,
252
+	-2404,
253
+	-2005,
254
+	-1606,
255
+	-1205,
256
+	-804,
257
+};
258
+
259
+// http://www.richardbrice.net/midi_notes.htm
260
+static const float midi_note_freq_table[128] = {
261
+	8.176,
262
+	8.662,
263
+	9.177,
264
+	9.723,
265
+	10.301,
266
+	10.913,
267
+	11.562,
268
+	12.250,
269
+	12.978,
270
+	13.750,
271
+	14.568,
272
+	15.434,
273
+	16.352,
274
+	17.324,
275
+	18.354,
276
+	19.445,
277
+	20.601,
278
+	21.826,
279
+	23.124,
280
+	24.499,
281
+	25.956,
282
+	27.500, // Lowest note on piano
283
+	29.135,
284
+	30.867,
285
+	32.703,
286
+	34.648,
287
+	36.708,
288
+	38.890,
289
+	41.203,
290
+	43.653,
291
+	46.249,
292
+	48.999,
293
+	51.913,
294
+	55.000,
295
+	58.270,
296
+	61.735,
297
+	65.406,
298
+	69.295,
299
+	73.416,
300
+	77.781,
301
+	82.406,
302
+	87.307,
303
+	92.499,
304
+	97.998,
305
+	103.82,
306
+	110.00,
307
+	116.54,
308
+	123.47,
309
+	130.81,
310
+	138.59,
311
+	146.83,
312
+	155.56,
313
+	164.81,
314
+	174.61,
315
+	184.99,
316
+	195.99,
317
+	207.65,
318
+	220.00,
319
+	233.08,
320
+	246.94,
321
+	261.63, // Middle-C
322
+	277.18,
323
+	293.66,
324
+	311.13,
325
+	329.63,
326
+	349.23,
327
+	369.99,
328
+	391.99,
329
+	415.31,
330
+	440.00,
331
+	466.16,
332
+	489.88,
333
+	523.25,
334
+	554.37,
335
+	587.33,
336
+	622.25,
337
+	659.26,
338
+	698.46,
339
+	739.99,
340
+	783.99,
341
+	830.61,
342
+	880.00,
343
+	932.32,
344
+	987.77,
345
+	1046.5,
346
+	1108.7,
347
+	1174.7,
348
+	1244.5,
349
+	1318.5,
350
+	1396.9,
351
+	1480.0,
352
+	1568.0,
353
+	1661.2,
354
+	1760.0,
355
+	1864.7,
356
+	1975.5,
357
+	2093.0,
358
+	2217.5,
359
+	2349.3,
360
+	2489.0,
361
+	2637.0,
362
+	2793.8,
363
+	2960.0,
364
+	3136.0,
365
+	3322.4,
366
+	3520.0,
367
+	3729.3,
368
+	3951.1,
369
+	4186.0, // Highest note on piano
370
+	4434.9,
371
+	4698.6,
372
+	4978.0,
373
+	5274.0,
374
+	5587.7,
375
+	5919.9,
376
+	6271.9,
377
+	6644.9,
378
+	7040.0,
379
+	7458.6,
380
+	7902.1,
381
+	8372.0,
382
+	8869.8,
383
+	9397.3,
384
+	9956.1,
385
+	10548.1,
386
+	11175.3,
387
+	11839.8,
388
+	12543.9,
389
+};

Loading…
Cancel
Save