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

Contents of /src/main.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26