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

Contents of /src/main.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26