/[paths]/src/main.c
ViewVC logotype

Contents of /src/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (show annotations)
Sat Aug 18 18:49:13 2012 UTC (7 years, 11 months ago) by ben
File MIME type: text/plain
File size: 10143 byte(s)
bugfix, cleaning, work for 2 instr and 2 voices per instr
1 /* Copyright (c) 2012, Benoit Rouits <brouits@free.fr>
2 * Some rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE
14 * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
16 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
17 * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
19 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <jack/jack.h>
32 #include <jack/midiport.h>
33
34 #include <config.h>
35 #include "graph.h"
36
37 #define MAX_VOICE 64
38 #define MAX_INST 128
39
40 #define error(str) fprintf(stderr, "[error]\t%s\n", str)
41
42 struct jack {
43 jack_client_t *client;
44 jack_transport_state_t state;
45 };
46
47 struct voice {
48 struct event* route;
49 int count;
50 int cur;
51 jack_time_t press;
52 };
53
54 struct instrument {
55 struct voice voices[MAX_VOICE];
56 int count;
57 int end;
58
59 unsigned char chan:4; /* 0-15 */
60 unsigned char prog; /* 0-127 */
61 unsigned char last_prog;
62
63 jack_port_t *out;
64 void* out_buf;
65
66 struct graph *graph;
67 };
68
69 struct app {
70 struct instrument instruments[MAX_INST];
71 int count;
72 int end;
73
74 struct jack *jack;
75 };
76
77 static int send_prog_change(struct app *app, int inst, int frame)
78 {
79 unsigned char *buf = jack_midi_event_reserve(app->instruments[inst].out_buf, frame, 2);
80 if (!buf) {
81 error("no memory, event lost");
82 return 1;
83 }
84 buf[1] = app->instruments[inst].prog;
85 buf[0] = 0xc0|app->instruments[inst].chan;
86 return 0;
87 }
88
89 int send_note_off(struct app *app, int inst, int frame, struct event *ev)
90 {
91 unsigned char *buf = jack_midi_event_reserve(app->instruments[inst].out_buf, frame, 3);
92 if (!buf) {
93 error("no memory, event lost");
94 return 1;
95 }
96 buf[2] = ev->velocity;
97 buf[1] = ev->pitch;
98 buf[0] = 0x80|app->instruments[inst].chan; /* note off */
99 fprintf(stderr, "off %d (%p)\n", ev->pitch, ev);
100 return 0;
101 }
102
103 int send_note_on(struct app *app, int inst, int frame, struct event *ev)
104 {
105 unsigned char *buf = jack_midi_event_reserve(app->instruments[inst].out_buf, frame, 3);
106 if (!buf) {
107 error("no memory, event lost");
108 return 1;
109 }
110 buf[2] = ev->velocity;
111 buf[1] = ev->pitch;
112 buf[0] = 0x90|app->instruments[inst].chan; /* note on */
113 fprintf(stderr, "on %d (%p)\n", ev->pitch, ev);
114 return 0;
115 }
116
117 static int jack_process_callback(jack_nframes_t nframes, void *ctx)
118 {
119 struct app *app;
120 jack_transport_state_t state;
121 int i, voice, inst;
122
123 app = ctx;
124
125 if (nframes <= 0) {
126 error("called process w/o frames");
127 return 0;
128 }
129
130 /* prepare all out buffers before writing into them */
131 for (i = 0; i < app->count; i++) {
132 void *port_buf = jack_port_get_buffer(app->instruments[i].out, nframes);
133 jack_midi_clear_buffer(port_buf);
134 app->instruments[i].out_buf = port_buf;
135 }
136
137 /* get transport state, act in consequence */
138 state = jack_transport_query(app->jack->client, NULL);
139 if (state == JackTransportStopped) {
140 if (app->jack->state == JackTransportRolling)
141 { /* send not off everywhere! */ }
142 app->jack->state = state;
143 return 0;
144 }
145 app->jack->state = state;
146
147 /* check end of all voices of all instruments */
148 if (app->end >= app->count)
149 return 0;
150
151 /* go browse all voice states and send events */
152 for (i = 0; i < nframes; i++) {
153 if (app->end >= app->count) {
154 fprintf(stderr, "tune ended (%d instruments)\n", app->end);
155 return 0;
156 }
157 for (inst = 0; inst < app->count; inst++) {
158 if (app->instruments[inst].end >= app->instruments[inst].count) {
159 if (app->instruments[inst].end == app->instruments[inst].count) {
160 app->end++;
161 fprintf(stderr, "instrument %d ended (%d voices)\n", inst, app->instruments[inst].end);
162 app->instruments[inst].end++; /* do not pass here again */
163 }
164 continue;
165 }
166 for (voice = 0; voice < app->instruments[inst].count; voice++) {
167 jack_time_t *press = &app->instruments[inst].voices[voice].press;
168 int *cur = &app->instruments[inst].voices[voice].cur;
169 if (*cur >= app->instruments[inst].voices[voice].count) {
170 if (*cur == app->instruments[inst].voices[voice].count) {
171 app->instruments[inst].end++;
172 fprintf(stderr, "instr. %d: voice %d ended (%d notes)\n", inst, voice, *cur);
173 (*cur)++; /* do not pass here again */
174 }
175 continue;
176 }
177 struct event *ev = &app->instruments[inst].voices[voice].route[*cur];
178
179 jack_time_t now = jack_get_time();
180
181 if (*press) { /* note must be released before passing to next note */
182 if (*press + ev->duration <= now) {
183 /* send a note off */
184 send_note_off(app, inst, i, ev);
185 *press = 0; /* release */
186 (*cur)++; /* go to next node */
187 }
188 } else { /* this is a new note */
189 /* set program change on start only */
190 if (app->instruments[inst].prog != app->instruments[inst].last_prog) {
191 send_prog_change(app, inst, i);
192 app->instruments[inst].last_prog = app->instruments[inst].prog;
193 }
194 send_note_on(app, inst, i, ev);
195 *press = now;
196 }
197 }
198 }
199 }
200
201 return 0;
202 }
203
204 static int jack_sync_callback(jack_transport_state_t state, jack_position_t *position, void *ctx)
205 {
206 struct app *app;
207
208 app = ctx;
209
210 if (state == JackTransportStarting) {
211 /* seek in paths (???) according to position->frame */
212 } else if (state == JackTransportStopped) {
213 }
214
215 return 1;
216 }
217
218 void jack_shutdown(void* ctx)
219 {
220 puts("jack vanished...");
221 }
222
223 int main (int argc, char *argv[])
224 {
225 struct graph *graph;
226 struct instrument instrument1;
227 struct instrument instrument2;
228 struct voice voice1;
229 struct voice voice2;
230 struct voice voice3;
231 struct voice voice4;
232 struct jack jack;
233 struct app app;
234
235 int i, err;
236
237 /* create random graph */
238 graph = graph_new(100);
239 graph_randomize2(graph, 3);
240
241 /* create 2 random routes à la Nancarrow */
242 memset(&voice1, 0, sizeof(voice1));
243 voice1.route = malloc(graph->count * sizeof(*voice1.route));
244 voice1.count = graph->count;
245 for (i = 0; i < voice1.count; i++)
246 voice1.route[i] = graph->nodes[i].event;
247
248 memset(&voice2, 0, sizeof(voice2));
249 voice2.route = malloc(graph->count * sizeof(*voice2.route));
250 voice2.count = graph->count;
251 for (i = 0; i < voice2.count; i++)
252 voice2.route[i] = graph->nodes[graph->count - i].event;
253
254 /* create 2 other random routes */
255 memset(&voice3, 0, sizeof(voice3));
256 voice3.route = malloc(graph->count * sizeof(*voice3.route));
257 voice3.count = graph->count;
258 for (i = 0; i < voice3.count; i++)
259 voice3.route[i] = graph->nodes[rand()%graph->count].event;
260
261 memset(&voice4, 0, sizeof(voice4));
262 voice4.route = malloc(graph->count * sizeof(*voice4.route));
263 voice4.count = graph->count;
264 for (i = 0; i < voice4.count; i++)
265 voice4.route[i] = voice3.route[graph->count - i];
266
267 /* initialize instruments */
268 memset(&instrument1, 0, sizeof(instrument1));
269 instrument1.graph = graph;
270
271 instrument1.voices[0] = voice1;
272 instrument1.voices[1] = voice2;
273 instrument1.count = 2;
274
275
276 memset(&instrument2, 0, sizeof(instrument2));
277 instrument2.graph = graph;
278
279 instrument2.voices[0] = voice3;
280 instrument2.voices[1] = voice4;
281 instrument2.count = 2;
282
283 /* initialize application context */
284 memset(&app, 0, sizeof(app));
285 app.jack = &jack;
286 app.count = 2;
287
288 app.instruments[0] = instrument1;
289 app.instruments[1] = instrument2;
290
291 /* mark it (...) */
292 app.instruments[0].chan = 0;
293 app.instruments[0].prog = 42;
294 app.instruments[0].voices[0].route[0].pitch = 42;
295 app.instruments[0].voices[0].route[0].duration = 4200000;
296 app.instruments[0].voices[1].route[0].pitch = 43;
297 app.instruments[0].voices[1].route[0].duration = 4300000;
298
299 app.instruments[1].chan = 1;
300 app.instruments[1].prog = 0;
301 app.instruments[1].voices[0].route[0].pitch = 44;
302 app.instruments[1].voices[0].route[0].duration = 4400000;
303 app.instruments[1].voices[1].route[0].pitch = 45;
304 app.instruments[1].voices[1].route[0].duration = 4500000;
305
306 /* init jack */
307 jack.client = jack_client_open(PACKAGE_NAME, JackNullOption, NULL);
308 if (jack.client == NULL) {
309 error("could not connect to jackd");
310 exit(EXIT_FAILURE);
311 }
312
313 err = jack_set_process_callback(jack.client, jack_process_callback, &app);
314
315 if (err) {
316 error("could not set jack process callback");
317 exit(EXIT_FAILURE);
318 }
319
320 err = jack_set_sync_callback(jack.client, jack_sync_callback, &app);
321
322 if (err) {
323 error("could not set jack sync callback");
324 exit(EXIT_FAILURE);
325 }
326
327 jack_on_shutdown(jack.client, jack_shutdown, &app);
328
329 /* allocate one jack port per instrument (midi outs) */
330 for (i = 0; i < app.count; i++) {
331 char name[32];
332 snprintf(name, 32, "out %d", i);
333 app.instruments[i].out = jack_port_register(jack.client, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
334 if (app.instruments[i].out == NULL) {
335 error("could not register a jack midi out port");
336 exit(EXIT_FAILURE);
337 }
338 }
339
340 /* activate jack */
341 if (jack_activate(jack.client)) {
342 error("could not activate jack client");
343 exit(EXIT_FAILURE);
344 }
345
346
347 fprintf(stderr, "==========\n");
348 /* start playing (event loop will sometime appear here) */
349 while (1)
350 sleep(1);
351 fprintf(stderr, "==========\n");
352
353 /* close jack */
354 jack_client_close (jack.client);
355
356 /* exit */
357 free(voice1.route);
358 free(voice2.route);
359 free(voice3.route);
360 free(voice4.route);
361 graph_destroy(graph);
362
363 exit(EXIT_SUCCESS);
364 }

  ViewVC Help
Powered by ViewVC 1.1.26