Browse Source

add command line options and cleanup

vampirefrog 3 years ago
parent
commit
b3134536e2
1 changed files with 159 additions and 136 deletions
  1. 159
    136
      main.c

+ 159
- 136
main.c View File

@@ -23,7 +23,6 @@
23 23
 #include <string.h>
24 24
 
25 25
 #include <jack/jack.h>
26
-#include <jack/transport.h>
27 26
 
28 27
 #include <asoundlib.h>
29 28
 
@@ -32,143 +31,150 @@ struct Synth synth;
32 31
 
33 32
 typedef jack_default_audio_sample_t sample_t;
34 33
 
35
-const double PI = 3.14;
36
-
34
+#define CLIENT_NAME "Vampi Synth"
37 35
 jack_client_t *client;
38
-jack_port_t *output_port_l, *output_port_r;
36
+jack_port_t *output_ports[2];
39 37
 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: vampisynth \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 process_silence (jack_nframes_t nframes) {
63
-	sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port_l, nframes);
64
-	memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
65
-	buffer = (sample_t *) jack_port_get_buffer (output_port_r, nframes);
66
-	memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
67
-}
38
+int verbose = 0;
68 39
 
69
-void process_audio (jack_nframes_t nframes) {
70
-	sample_t *buffer_l = (sample_t *) jack_port_get_buffer (output_port_l, nframes);
71
-	sample_t *buffer_r = (sample_t *) jack_port_get_buffer (output_port_r, nframes);
40
+int process (jack_nframes_t nframes, void *arg) {
41
+	sample_t *buffers[2];
42
+	buffers[0] = (sample_t *) jack_port_get_buffer (output_ports[0], nframes);
43
+	buffers[1] = (sample_t *) jack_port_get_buffer (output_ports[1], nframes);
72 44
 	for(int i = 0; i < nframes; i++) {
73
-		int16_t out[2];
45
+		float out[2];
74 46
 		synth_render_sample(&synth, out);
75
-		buffer_l[i] = out[0] / 32767.0;
76
-		buffer_r[i] = out[1] / 32767.0;
47
+		buffers[0][i] = out[0];
48
+		buffers[1][i] = out[1];
77 49
 	}
78
-}
79
-
80
-int process (jack_nframes_t nframes, void *arg) {
81
-	if (transport_aware) {
82
-		jack_position_t pos;
83
-
84
-		if (jack_transport_query (client, &pos)
85
-				!= JackTransportRolling) {
86
-
87
-			process_silence (nframes);
88
-			return 0;
89
-		}
90
-		offset = pos.frame % wave_length;
91
-	}
92
-	process_audio (nframes);
93 50
 	return 0;
94 51
 }
95 52
 
96
-int
97
-sample_rate_change () {
98
-	printf("Sample rate has changed! Exiting...\n");
99
-	exit(-1);
100
-}
101
-
102 53
 static char *midi_note_names[12] = {
103
-	"C",
104
-	"C#",
105
-	"D",
106
-	"D#",
107
-	"E",
108
-	"F",
109
-	"F#",
110
-	"G",
111
-	"G#",
112
-	"A",
113
-	"A#",
114
-	"B",
54
+	"C", "C#", "D", "D#", "E", "F",
55
+	"F#", "G", "G#", "A", "A#", "B",
115 56
 };
116 57
 
117 58
 const char *midi_note_name(int note) {
118 59
 	return midi_note_names[note % 12];
119 60
 }
120 61
 
121
-snd_seq_t *open_seq();
122
-void midi_action(snd_seq_t *seq_handle);
123
-
124
-snd_seq_t *open_seq() {
125
-
126
-	snd_seq_t *seq_handle;
127
-	int portid;
128
-
129
-	if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, 0) < 0) {
130
-		fprintf(stderr, "Error opening ALSA sequencer.\n");
131
-		exit(1);
132
-	}
133
-	snd_seq_set_client_name(seq_handle, "Vampi Synth");
134
-	if ((portid = snd_seq_create_simple_port(seq_handle, "Cornhole",
135
-						SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
136
-						SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
137
-		fprintf(stderr, "Error creating sequencer port.\n");
138
-		exit(1);
62
+const char *midi_cc_name(int cc) {
63
+	switch(cc) {
64
+		case MIDI_CTL_ALL_NOTES_OFF: return "All notes off";
65
+		case MIDI_CTL_ALL_SOUNDS_OFF: return "All sounds off";
66
+		case MIDI_CTL_DATA_DECREMENT: return "Data Decrement";
67
+		case MIDI_CTL_DATA_INCREMENT: return "Data Increment";
68
+		case MIDI_CTL_E1_REVERB_DEPTH: return "E1 Reverb Depth";
69
+		case MIDI_CTL_E2_TREMOLO_DEPTH: return "E2 Tremolo Depth";
70
+		case MIDI_CTL_E3_CHORUS_DEPTH: return "E3 Chorus Depth";
71
+		case MIDI_CTL_E4_DETUNE_DEPTH: return "E4 Detune Depth";
72
+		case MIDI_CTL_E5_PHASER_DEPTH: return "E5 Phaser Depth";
73
+		case MIDI_CTL_GENERAL_PURPOSE5: return "General purpose 5";
74
+		case MIDI_CTL_GENERAL_PURPOSE6: return "General purpose 6";
75
+		case MIDI_CTL_GENERAL_PURPOSE7: return "General purpose 7";
76
+		case MIDI_CTL_GENERAL_PURPOSE8: return "General purpose 8";
77
+		case MIDI_CTL_HOLD2: return "Hold2";
78
+		case MIDI_CTL_LEGATO_FOOTSWITCH: return "Legato foot switch";
79
+		case MIDI_CTL_LOCAL_CONTROL_SWITCH: return "Local control switch";
80
+		case MIDI_CTL_LSB_BALANCE: return "Balance";
81
+		case MIDI_CTL_LSB_BANK: return "Bank selection";
82
+		case MIDI_CTL_LSB_BREATH: return "Breath";
83
+		case MIDI_CTL_LSB_DATA_ENTRY: return "Data entry";
84
+		case MIDI_CTL_LSB_EFFECT1: return "Effect1";
85
+		case MIDI_CTL_LSB_EFFECT2: return "Effect2";
86
+		case MIDI_CTL_LSB_EXPRESSION: return "Expression";
87
+		case MIDI_CTL_LSB_FOOT: return "Foot";
88
+		case MIDI_CTL_LSB_GENERAL_PURPOSE1: return "General purpose 1";
89
+		case MIDI_CTL_LSB_GENERAL_PURPOSE2: return "General purpose 2";
90
+		case MIDI_CTL_LSB_GENERAL_PURPOSE3: return "General purpose 3";
91
+		case MIDI_CTL_LSB_GENERAL_PURPOSE4: return "General purpose 4";
92
+		case MIDI_CTL_LSB_MAIN_VOLUME: return "Main volume";
93
+		case MIDI_CTL_LSB_MODWHEEL: return "Modulation";
94
+		case MIDI_CTL_LSB_PAN: return "Panpot";
95
+		case MIDI_CTL_LSB_PORTAMENTO_TIME: return "Portamento time";
96
+		case MIDI_CTL_MONO1: return "Mono1";
97
+		case MIDI_CTL_MONO2: return "Mono2";
98
+		case MIDI_CTL_MSB_BALANCE: return "Balance";
99
+		case MIDI_CTL_MSB_BANK: return "Bank selection";
100
+		case MIDI_CTL_MSB_BREATH: return "Breath";
101
+		case MIDI_CTL_MSB_DATA_ENTRY: return "Data entry";
102
+		case MIDI_CTL_MSB_EFFECT1: return "Effect1";
103
+		case MIDI_CTL_MSB_EFFECT2: return "Effect2";
104
+		case MIDI_CTL_MSB_EXPRESSION: return "Expression";
105
+		case MIDI_CTL_MSB_FOOT: return "Foot";
106
+		case MIDI_CTL_MSB_GENERAL_PURPOSE1: return "General purpose 1";
107
+		case MIDI_CTL_MSB_GENERAL_PURPOSE2: return "General purpose 2";
108
+		case MIDI_CTL_MSB_GENERAL_PURPOSE3: return "General purpose 3";
109
+		case MIDI_CTL_MSB_GENERAL_PURPOSE4: return "General purpose 4";
110
+		case MIDI_CTL_MSB_MAIN_VOLUME: return "Main volume";
111
+		case MIDI_CTL_MSB_MODWHEEL: return "Modulation";
112
+		case MIDI_CTL_MSB_PAN: return "Panpot";
113
+		case MIDI_CTL_MSB_PORTAMENTO_TIME: return "Portamento time";
114
+		case MIDI_CTL_NONREG_PARM_NUM_LSB: return "Non-registered parameter number";
115
+		case MIDI_CTL_NONREG_PARM_NUM_MSB: return "Non-registered parameter number";
116
+		case MIDI_CTL_OMNI_OFF: return "Omni off";
117
+		case MIDI_CTL_OMNI_ON: return "Omni on";
118
+		case MIDI_CTL_PORTAMENTO: return "Portamento";
119
+		case MIDI_CTL_PORTAMENTO_CONTROL: return "Portamento control";
120
+		case MIDI_CTL_REGIST_PARM_NUM_LSB: return "Registered parameter number";
121
+		case MIDI_CTL_REGIST_PARM_NUM_MSB: return "Registered parameter number";
122
+		case MIDI_CTL_RESET_CONTROLLERS: return "Reset Controllers";
123
+		case MIDI_CTL_SC10: return "SC10";
124
+		case MIDI_CTL_SC1_SOUND_VARIATION: return "SC1 Sound Variation";
125
+		case MIDI_CTL_SC2_TIMBRE: return "SC2 Timbre";
126
+		case MIDI_CTL_SC3_RELEASE_TIME: return "SC3 Release Time";
127
+		case MIDI_CTL_SC4_ATTACK_TIME: return "SC4 Attack Time";
128
+		case MIDI_CTL_SC5_BRIGHTNESS: return "SC5 Brightness";
129
+		case MIDI_CTL_SC6: return "SC6";
130
+		case MIDI_CTL_SC7: return "SC7";
131
+		case MIDI_CTL_SC8: return "SC8";
132
+		case MIDI_CTL_SC9: return "SC9";
133
+		case MIDI_CTL_SOFT_PEDAL: return "Soft pedal";
134
+		case MIDI_CTL_SOSTENUTO: return "Sostenuto";
135
+		case MIDI_CTL_SUSTAIN: return "Sustain pedal";
139 136
 	}
140 137
 
141
-	snd_seq_connect_from(seq_handle, portid, 36, 0);
142
-	return(seq_handle);
138
+	return "Unknown";
143 139
 }
144 140
 
145 141
 void midi_action(snd_seq_t *seq_handle) {
146
-
147 142
 	snd_seq_event_t *ev;
148 143
 
149 144
 	do {
150 145
 		snd_seq_event_input(seq_handle, &ev);
151 146
 		switch (ev->type) {
152 147
 			case SND_SEQ_EVENT_NOTEON:
153
-				// printf("Note on %d (%s) %d\n", ev->data.note.note, midi_note_name(ev->data.note.note), ev->data.note.velocity);
148
+				if(verbose)
149
+					printf("Note on %s (%d) %d\n", midi_note_name(ev->data.note.note), ev->data.note.note, ev->data.note.velocity);
154 150
 				synth_note_on(&synth, ev->data.note.note, ev->data.note.velocity);
155 151
 				break;
156 152
 			case SND_SEQ_EVENT_NOTEOFF:
157
-				// printf("Note off %d\n", ev->data.note.note);
153
+				if(verbose)
154
+					printf("Note off %s (%d) %d\n", midi_note_name(ev->data.note.note), ev->data.note.note, ev->data.note.velocity);
158 155
 				synth_note_off(&synth, ev->data.note.note, ev->data.note.velocity);
159 156
 				break;
160 157
 			case SND_SEQ_EVENT_CONTROLLER:
161
-				// printf("CC %d %d\n", ev->data.control.param, ev->data.control.value);
158
+				if(verbose)
159
+					printf("CC 0x%02x (%s) %d\n", ev->data.control.param, midi_cc_name(ev->data.control.param), ev->data.control.value);
162 160
 				if(ev->data.control.param == 91) {
161
+					if(verbose)
162
+						printf("Unison spread %d\n", ev->data.control.value);
163 163
 					synth_set_unison_spread(&synth, ev->data.control.value);
164 164
 				}
165 165
 				if(ev->data.control.param == 93) {
166
+					if(verbose)
167
+						printf("Stereo spread %d\n", ev->data.control.value);
166 168
 					synth_set_stereo_spread(&synth, ev->data.control.value);
167 169
 				}
168 170
 				if(ev->data.control.param == 74) {
171
+					if(verbose)
172
+						printf("Cutoff %d\n", ev->data.control.value);
169 173
 					synth_set_cutoff_freq(&synth, ev->data.control.value);
170 174
 				}
171 175
 				if(ev->data.control.param == 71) {
176
+					if(verbose)
177
+						printf("Resonance %d\n", ev->data.control.value);
172 178
 					synth_set_resonance(&synth, ev->data.control.value);
173 179
 				}
174 180
 				break;
@@ -177,22 +183,17 @@ void midi_action(snd_seq_t *seq_handle) {
177 183
 	} while (snd_seq_event_input_pending(seq_handle, 0) > 0);
178 184
 }
179 185
 
180
-
181 186
 int main(int argc, char **argv) {
182
-	sample_t scale;
183
-	int i, attack_length, decay_length;
184 187
 	int option_index;
185 188
 	int opt;
186
-	char *client_name = 0;
187
-	char *bpm_string = "synth out";
188
-	int verbose = 0;
189
+	char *client_name = CLIENT_NAME;
190
+	char *input_seq_addr = 0;
189 191
 	jack_status_t status;
190 192
 
191
-	const char *options = "f:A:D:a:d:b:n:thv";
192
-	struct option long_options[] =
193
-	{
193
+	const char *options = "n:p:hv";
194
+	struct option long_options[] = {
194 195
 		{"name", 1, 0, 'n'},
195
-		{"transport", 0, 0, 't'},
196
+		{"port", 1, 0, 'p'},
196 197
 		{"help", 0, 0, 'h'},
197 198
 		{"verbose", 0, 0, 'v'},
198 199
 		{0, 0, 0, 0}
@@ -204,35 +205,38 @@ int main(int argc, char **argv) {
204 205
 			client_name = (char *) malloc (strlen (optarg) * sizeof (char));
205 206
 			strcpy (client_name, optarg);
206 207
 			break;
207
-		case 't':
208
-			transport_aware = 1;
208
+		case 'p':
209
+			input_seq_addr = optarg;
209 210
 			break;
210
-		default:
211
-			fprintf (stderr, "unknown option %c\n", opt);
212
-		case 'h':
213
-			usage ();
214
-			return -1;
215 211
 		case 'v':
216 212
 			verbose = 1;
217 213
 			break;
214
+		default:
215
+			fprintf (stderr, "Unknown option %c\n", opt);
216
+		case 'h':
217
+			fprintf(stderr, "usage: %s [options]\n"
218
+				"\t-p, --port <port name>   Input port for sequencer events (MIDI keyboard)\n"
219
+				"\t-n, --name <name>.       Jack client name. Default: " CLIENT_NAME " ]\n"
220
+				"\t-v    Verbose\n"
221
+				"\t-h    Help\n",
222
+				argv[0]
223
+			);
224
+			return -1;
218 225
 		}
219 226
 	}
220 227
 
221 228
 	/* Initial Jack setup, get sample rate */
222
-	if (!client_name) {
223
-		client_name = strdup("vampi va");
224
-	}
225 229
 	if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) {
226 230
 		fprintf (stderr, "jack server not running?\n");
227 231
 		return 1;
228 232
 	}
229 233
 	jack_set_process_callback(client, process, 0);
230
-	output_port_l = jack_port_register(client, "Synth Out L", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
231
-	output_port_r = jack_port_register(client, "Synth Out R", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
234
+	output_ports[0] = jack_port_register(client, "Synth Out L", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
235
+	output_ports[1] = jack_port_register(client, "Synth Out R", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
232 236
 
233 237
 	sr = jack_get_sample_rate(client);
234 238
 
235
-	if (jack_activate (client)) {
239
+	if (jack_activate(client)) {
236 240
 		fprintf (stderr, "cannot activate client");
237 241
 		exit (1);
238 242
 	}
@@ -244,29 +248,26 @@ int main(int argc, char **argv) {
244 248
 		exit (1);
245 249
 	}
246 250
 
247
-	if (jack_connect (client, jack_port_name (output_port_l), ports[0])) {
251
+	if (jack_connect (client, jack_port_name (output_ports[0]), ports[0])) {
248 252
 		fprintf (stderr, "cannot connect input ports\n");
249 253
 	}
250
-	if (jack_connect (client, jack_port_name (output_port_r), ports[1])) {
254
+
255
+	if (jack_connect (client, jack_port_name (output_ports[1]), ports[1])) {
251 256
 		fprintf (stderr, "cannot connect input ports\n");
252 257
 	}
253 258
 
254
-	// struct Filter f;
255
-	// for(i = 20; i <= 20000; i+=10) {
256
-	// 	for(int j = 1; j <= 10; j++) {
257
-	// 		filter_set_cutoff_q(&f, i, j);
258
-	// 	}
259
-	// }
260
-	// return 0;
261
-
262 259
 	synth_init(&synth);
263
-	synth.attack = 100;
264
-	synth.decay = 100;
265
-	synth.sustain = 80;
266
-	synth.release = 100;
267
-
268
-
269
-	if (jack_activate (client)) {
260
+	synth.osc_env.attack = 2;
261
+	synth.osc_env.decay = 100;
262
+	synth.osc_env.sustain = 90;
263
+	synth.osc_env.release = 100;
264
+	synth.filter_env.attack = 1000;
265
+	synth.filter_env.decay = 200;
266
+	synth.filter_env.sustain = 90;
267
+	synth.filter_env.release = 100;
268
+	synth.monophonic = 1;
269
+
270
+	if (jack_activate(client)) {
270 271
 		fprintf (stderr, "cannot activate client");
271 272
 		return 1;
272 273
 	}
@@ -274,8 +275,30 @@ int main(int argc, char **argv) {
274 275
 	snd_seq_t *seq_handle;
275 276
 	int npfd;
276 277
 	struct pollfd *pfd;
278
+	int portid;
279
+
280
+	if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, 0) < 0) {
281
+		fprintf(stderr, "Error opening ALSA sequencer.\n");
282
+		exit(1);
283
+	}
284
+	snd_seq_set_client_name(seq_handle, client_name);
285
+	if ((portid = snd_seq_create_simple_port(seq_handle, "Cornhole",
286
+						SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
287
+						SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
288
+		fprintf(stderr, "Error creating sequencer port.\n");
289
+		exit(1);
290
+	}
291
+
292
+	snd_seq_addr_t seq_input_port;
293
+	if(input_seq_addr) {
294
+		if(snd_seq_parse_address(seq_handle, &seq_input_port, input_seq_addr) == 0) {
295
+			snd_seq_connect_from(seq_handle, portid, seq_input_port.client, seq_input_port.port);
296
+		} else {
297
+			fprintf(stderr, "Could not parse port: %s\n", input_seq_addr);
298
+			exit(1);
299
+		}
300
+	}
277 301
 
278
-	seq_handle = open_seq();
279 302
 	npfd = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
280 303
 	pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
281 304
 	snd_seq_poll_descriptors(seq_handle, pfd, npfd, POLLIN);

Loading…
Cancel
Save