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

Contents of /src/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 33 - (show annotations)
Sat Aug 18 16:14:15 2012 UTC (7 years, 11 months ago) by ben
File MIME type: text/plain
File size: 8360 byte(s)
use 2 voices for more fun
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
62 jack_port_t *out;
63 void* out_buf;
64
65 struct graph *graph;
66 };
67
68 struct app {
69 struct instrument* instruments;
70 int count;
71 int end;
72
73 struct jack *jack;
74 };
75
76 static int jack_process_callback(jack_nframes_t nframes, void *ctx)
77 {
78 struct app *app;
79 jack_transport_state_t state;
80 int i, voice, inst;
81 static unsigned char last_prog = 0;
82
83 app = ctx;
84
85 if (nframes <= 0) {
86 error("called process w/o frames");
87 return 0;
88 }
89
90 /* prepare all out buffers before writing into them */
91 for (i = 0; i < app->count; i++) {
92 void *port_buf = jack_port_get_buffer(app->instruments[i].out, nframes);
93 jack_midi_clear_buffer(port_buf);
94 app->instruments[i].out_buf = port_buf;
95 }
96
97 /* get transport state, act in consequence */
98 state = jack_transport_query(app->jack->client, NULL);
99 if (state == JackTransportStopped) {
100 if (app->jack->state == JackTransportRolling)
101 { /* send not off everywhere! */ }
102 app->jack->state = state;
103 return 0;
104 }
105 app->jack->state = state;
106
107 /* check end of all voices of all instruments */
108 if (app->end >= app->count)
109 return 0;
110
111 /* go browse all voice states and send events */
112 for (i = 0; i < nframes; i++) {
113 if (app->end >= app->count) {
114 fprintf(stderr, "tune ended (%d instruments)\n", app->end);
115 return 0;
116 }
117 for (inst = 0; inst < app->count; inst++) {
118 if (app->instruments[inst].end >= app->instruments[inst].count) {
119 app->end++;
120 fprintf(stderr, "instrument ended (%d voices)\n", app->instruments[inst].end);
121 continue;
122 }
123 if (app->instruments[inst].prog != last_prog) {
124 unsigned char *buf = jack_midi_event_reserve(app->instruments[inst].out_buf, i, 2);
125 if (!buf) {
126 error("no memory, event lost");
127 return 0;
128 }
129 buf[1] = app->instruments[inst].prog;
130 buf[0] = 0xc0|app->instruments[inst].chan;
131 last_prog = app->instruments[inst].prog;
132 }
133 for (voice = 0; voice < app->instruments[inst].count; voice++) {
134 jack_time_t *press = &app->instruments[inst].voices[voice].press;
135 int *cur = &app->instruments[inst].voices[voice].cur;
136 if (*cur >= app->instruments[inst].voices[voice].count) {
137 app->instruments[inst].end++;
138 fprintf(stderr, "voice ended (%d notes)\n", *cur);
139 continue;
140 }
141 struct event *ev = &app->instruments[inst].voices[voice].route[*cur];
142
143 jack_time_t now = jack_get_time();
144
145 if (*press) { /* note must be released before passing to next note */
146 if (*press + ev->duration <= now) {
147 unsigned char *buf = jack_midi_event_reserve(app->instruments[inst].out_buf, i, 3);
148 if (!buf) {
149 error("no memory, event lost");
150 return 0;
151 }
152 buf[2] = ev->velocity;
153 buf[1] = ev->pitch;
154 buf[0] = 0x80|app->instruments[inst].chan; /* note off */
155 *press = 0; /* release */
156 (*cur)++; /* go to next node */
157 fprintf(stderr, "off %d (%p)\n", ev->pitch, ev);
158 }
159 } else { /* this is a new note */
160 unsigned char *buf = jack_midi_event_reserve(app->instruments[inst].out_buf, i, 3);
161 if (!buf) {
162 error("no memory, event lost");
163 return 0;
164 }
165 buf[2] = ev->velocity;
166 buf[1] = ev->pitch;
167 buf[0] = 0x90|app->instruments[inst].chan; /* note on */
168 *press = now;
169 fprintf(stderr, "on %d (%p)\n", ev->pitch, ev);
170 }
171 }
172 }
173 }
174
175 return 0;
176 }
177
178 static int jack_sync_callback(jack_transport_state_t state, jack_position_t *position, void *ctx)
179 {
180 struct app *app;
181
182 app = ctx;
183
184 if (state == JackTransportStarting) {
185 /* seek in paths (???) according to position->frame */
186 } else if (state == JackTransportStopped) {
187 }
188
189 return 1;
190 }
191
192 void jack_shutdown(void* ctx)
193 {
194 puts("jack vanished...");
195 }
196
197 int main (int argc, char *argv[])
198 {
199 struct graph *graph;
200 struct instrument instrument;
201 struct voice voice1;
202 struct voice voice2;
203 struct jack jack;
204 struct app app;
205
206 int i, err;
207
208 /* create random graph */
209 graph = graph_new(100);
210 graph_randomize2(graph, 3);
211
212 /* initialize a solo instrument */
213 memset(&instrument, 0, sizeof(instrument));
214 instrument.graph = graph;
215
216 /* initialize application context */
217 memset(&app, 0, sizeof(app));
218 app.jack = &jack;
219 app.instruments = &instrument;
220 app.count = 1;
221
222 /* create 2 random routes à la Nancarrow */
223 memset(&voice1, 0, sizeof(voice1));
224 voice1.route = malloc(graph->count * sizeof(*voice1.route));
225 voice1.count = graph->count;
226 for (i = 0; i < voice1.count; i++)
227 voice1.route[i] = graph->nodes[i].event;
228
229 memset(&voice2, 0, sizeof(voice2));
230 voice2.route = malloc(graph->count * sizeof(*voice2.route));
231 voice2.count = graph->count;
232 for (i = 0; i < voice2.count; i++)
233 voice2.route[i] = graph->nodes[graph->count - i].event;
234
235 instrument.voices[0] = voice1;
236 instrument.voices[1] = voice2;
237 instrument.count = 2;
238
239 /* mark it (...) */
240 app.instruments[0].chan = 0;
241 app.instruments[0].prog = 0;
242 app.instruments[0].voices[0].route[0].pitch = 42;
243 app.instruments[0].voices[0].route[0].duration = 4200000;
244 app.instruments[0].voices[1].route[0].pitch = 43;
245 app.instruments[0].voices[1].route[0].duration = 4300000;
246
247 /* init jack */
248 jack.client = jack_client_open(PACKAGE_NAME, JackNullOption, NULL);
249 if (jack.client == NULL) {
250 error("could not connect to jackd");
251 exit(EXIT_FAILURE);
252 }
253
254 err = jack_set_process_callback(jack.client, jack_process_callback, &app);
255
256 if (err) {
257 error("could not set jack process callback");
258 exit(EXIT_FAILURE);
259 }
260
261 err = jack_set_sync_callback(jack.client, jack_sync_callback, &app);
262
263 if (err) {
264 error("could not set jack sync callback");
265 exit(EXIT_FAILURE);
266 }
267
268 jack_on_shutdown(jack.client, jack_shutdown, &app);
269
270 /* allocate one jack port per instrument (midi outs) */
271 for (i = 0; i < app.count; i++) {
272 char name[32];
273 snprintf(name, 32, "out %d", i);
274 app.instruments[i].out = jack_port_register(jack.client, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
275 if (app.instruments[i].out == NULL) {
276 error("could not register a jack midi out port");
277 exit(EXIT_FAILURE);
278 }
279 }
280
281 /* activate jack */
282 if (jack_activate(jack.client)) {
283 error("could not activate jack client");
284 exit(EXIT_FAILURE);
285 }
286
287
288 fprintf(stderr, "==========\n");
289 /* start playing (event loop will sometime appear here) */
290 while (1)
291 sleep(1);
292 fprintf(stderr, "==========\n");
293
294 /* close jack */
295 jack_client_close (jack.client);
296
297 /* exit */
298 free(voice1.route);
299 free(voice2.route);
300 graph_destroy(graph);
301
302 exit(EXIT_SUCCESS);
303 }

  ViewVC Help
Powered by ViewVC 1.1.26