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

Annotation of /src/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 33 - (hide annotations)
Sat Aug 18 16:14:15 2012 UTC (8 years, 1 month ago) by ben
File MIME type: text/plain
File size: 8360 byte(s)
use 2 voices for more fun
1 ben 18 /* 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 ben 6 #include <stdio.h>
28 ben 15 #include <stdlib.h>
29     #include <string.h>
30    
31     #include <jack/jack.h>
32     #include <jack/midiport.h>
33    
34     #include <config.h>
35 ben 6 #include "graph.h"
36    
37 ben 23 #define MAX_VOICE 64
38     #define MAX_INST 128
39 ben 15
40 ben 18 #define error(str) fprintf(stderr, "[error]\t%s\n", str)
41 ben 15
42     struct jack {
43     jack_client_t *client;
44 ben 21 jack_transport_state_t state;
45 ben 15 };
46    
47 ben 21 struct voice {
48     struct event* route;
49 ben 16 int count;
50 ben 15 int cur;
51 ben 24 jack_time_t press;
52 ben 15 };
53    
54 ben 21 struct instrument {
55 ben 23 struct voice voices[MAX_VOICE];
56 ben 25 int count;
57     int end;
58    
59 ben 29 unsigned char chan:4; /* 0-15 */
60     unsigned char prog; /* 0-127 */
61    
62 ben 24 jack_port_t *out;
63     void* out_buf;
64 ben 25
65 ben 15 struct graph *graph;
66 ben 21 };
67    
68     struct app {
69     struct instrument* instruments;
70     int count;
71 ben 25 int end;
72    
73 ben 15 struct jack *jack;
74     };
75    
76     static int jack_process_callback(jack_nframes_t nframes, void *ctx)
77 ben 11 {
78 ben 21 struct app *app;
79     jack_transport_state_t state;
80 ben 24 int i, voice, inst;
81 ben 29 static unsigned char last_prog = 0;
82 ben 15
83 ben 21 app = ctx;
84 ben 15
85 ben 25 if (nframes <= 0) {
86     error("called process w/o frames");
87 ben 15 return 0;
88 ben 25 }
89 ben 15
90 ben 24 /* 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 ben 21 /* get transport state, act in consequence */
98 ben 26 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 ben 24
107 ben 21 /* check end of all voices of all instruments */
108 ben 25 if (app->end >= app->count)
109     return 0;
110 ben 24
111 ben 21 /* go browse all voice states and send events */
112 ben 25 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 ben 33 fprintf(stderr, "instrument ended (%d voices)\n", app->instruments[inst].end);
121 ben 25 continue;
122     }
123 ben 29 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 ben 31 last_prog = app->instruments[inst].prog;
132 ben 29 }
133 ben 24 for (voice = 0; voice < app->instruments[inst].count; voice++) {
134 ben 25 jack_time_t *press = &app->instruments[inst].voices[voice].press;
135 ben 24 int *cur = &app->instruments[inst].voices[voice].cur;
136 ben 25 if (*cur >= app->instruments[inst].voices[voice].count) {
137     app->instruments[inst].end++;
138 ben 33 fprintf(stderr, "voice ended (%d notes)\n", *cur);
139 ben 24 continue;
140 ben 25 }
141 ben 24 struct event *ev = &app->instruments[inst].voices[voice].route[*cur];
142 ben 16
143 ben 25 jack_time_t now = jack_get_time();
144    
145     if (*press) { /* note must be released before passing to next note */
146 ben 29 if (*press + ev->duration <= now) {
147 ben 27 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 ben 24 buf[2] = ev->velocity;
153     buf[1] = ev->pitch;
154 ben 29 buf[0] = 0x80|app->instruments[inst].chan; /* note off */
155     *press = 0; /* release */
156     (*cur)++; /* go to next node */
157 ben 24 fprintf(stderr, "off %d (%p)\n", ev->pitch, ev);
158     }
159 ben 25 } else { /* this is a new note */
160 ben 27 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 ben 24 buf[2] = ev->velocity;
166     buf[1] = ev->pitch;
167 ben 29 buf[0] = 0x90|app->instruments[inst].chan; /* note on */
168 ben 24 *press = now;
169     fprintf(stderr, "on %d (%p)\n", ev->pitch, ev);
170     }
171     }
172 ben 25 }
173     }
174 ben 24
175 ben 15 return 0;
176     }
177    
178     static int jack_sync_callback(jack_transport_state_t state, jack_position_t *position, void *ctx)
179     {
180 ben 26 struct app *app;
181 ben 15
182 ben 26 app = ctx;
183 ben 15
184     if (state == JackTransportStarting) {
185 ben 21 /* seek in paths (???) according to position->frame */
186 ben 15 } else if (state == JackTransportStopped) {
187 ben 11 }
188 ben 15
189     return 1;
190 ben 11 }
191    
192 ben 21 void jack_shutdown(void* ctx)
193 ben 17 {
194     puts("jack vanished...");
195     }
196    
197 ben 15 int main (int argc, char *argv[])
198 ben 6 {
199 ben 25 struct graph *graph;
200 ben 21 struct instrument instrument;
201 ben 33 struct voice voice1;
202     struct voice voice2;
203 ben 25 struct jack jack;
204     struct app app;
205 ben 6
206 ben 24 int i, err;
207 ben 15
208     /* create random graph */
209 ben 16 graph = graph_new(100);
210 ben 15 graph_randomize2(graph, 3);
211    
212 ben 25 /* initialize a solo instrument */
213 ben 21 memset(&instrument, 0, sizeof(instrument));
214     instrument.graph = graph;
215 ben 25
216     /* initialize application context */
217     memset(&app, 0, sizeof(app));
218 ben 21 app.jack = &jack;
219     app.instruments = &instrument;
220     app.count = 1;
221 ben 15
222 ben 33 /* 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 ben 15
229 ben 33 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 ben 21 /* mark it (...) */
240 ben 29 app.instruments[0].chan = 0;
241     app.instruments[0].prog = 0;
242 ben 21 app.instruments[0].voices[0].route[0].pitch = 42;
243 ben 29 app.instruments[0].voices[0].route[0].duration = 4200000;
244 ben 33 app.instruments[0].voices[1].route[0].pitch = 43;
245     app.instruments[0].voices[1].route[0].duration = 4300000;
246 ben 21
247 ben 15 /* 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 ben 21 err = jack_set_process_callback(jack.client, jack_process_callback, &app);
255 ben 15
256     if (err) {
257     error("could not set jack process callback");
258     exit(EXIT_FAILURE);
259     }
260    
261 ben 21 err = jack_set_sync_callback(jack.client, jack_sync_callback, &app);
262 ben 15
263     if (err) {
264     error("could not set jack sync callback");
265     exit(EXIT_FAILURE);
266     }
267    
268 ben 21 jack_on_shutdown(jack.client, jack_shutdown, &app);
269 ben 17
270 ben 24 /* 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 ben 15 }
280    
281     /* activate jack */
282     if (jack_activate(jack.client)) {
283     error("could not activate jack client");
284     exit(EXIT_FAILURE);
285     }
286    
287 ben 26
288     fprintf(stderr, "==========\n");
289 ben 33 /* start playing (event loop will sometime appear here) */
290     while (1)
291     sleep(1);
292 ben 26 fprintf(stderr, "==========\n");
293 ben 15
294     /* close jack */
295 ben 16 jack_client_close (jack.client);
296 ben 15
297     /* exit */
298 ben 33 free(voice1.route);
299     free(voice2.route);
300 ben 10 graph_destroy(graph);
301 ben 15
302     exit(EXIT_SUCCESS);
303 ben 6 }

  ViewVC Help
Powered by ViewVC 1.1.26