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

Contents of /src/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 27 - (show annotations)
Sat Aug 18 09:45:16 2012 UTC (7 years, 11 months ago) by ben
File MIME type: text/plain
File size: 7197 byte(s)
fix midi event storm b/w ON and OFF (do not reserve event when nothing to feed)
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
129 jack_time_t now = jack_get_time();
130
131 if (*press) { /* note must be released before passing to next note */
132 if (*press + ev->duration < now) {
133 unsigned char *buf = jack_midi_event_reserve(app->instruments[inst].out_buf, i, 3);
134 if (!buf) {
135 error("no memory, event lost");
136 return 0;
137 }
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 unsigned char *buf = jack_midi_event_reserve(app->instruments[inst].out_buf, i, 3);
147 if (!buf) {
148 error("no memory, event lost");
149 return 0;
150 }
151 buf[2] = ev->velocity;
152 buf[1] = ev->pitch;
153 buf[0] = 0x90; /* note on */
154 *press = now;
155 fprintf(stderr, "on %d (%p)\n", ev->pitch, ev);
156 }
157 }
158 }
159 }
160
161 return 0;
162 }
163
164 static int jack_sync_callback(jack_transport_state_t state, jack_position_t *position, void *ctx)
165 {
166 struct app *app;
167
168 app = ctx;
169
170 if (state == JackTransportStarting) {
171 /* seek in paths (???) according to position->frame */
172 } else if (state == JackTransportStopped) {
173 }
174
175 return 1;
176 }
177
178 void jack_shutdown(void* ctx)
179 {
180 puts("jack vanished...");
181 }
182
183 int main (int argc, char *argv[])
184 {
185 struct graph *graph;
186 struct instrument instrument;
187 struct voice voice;
188 struct jack jack;
189 struct app app;
190
191 int i, err;
192
193 /* create random graph */
194 graph = graph_new(100);
195 graph_randomize2(graph, 3);
196
197 /* initialize a solo instrument */
198 memset(&instrument, 0, sizeof(instrument));
199 instrument.graph = graph;
200
201 /* initialize application context */
202 memset(&app, 0, sizeof(app));
203 app.jack = &jack;
204 app.instruments = &instrument;
205 app.count = 1;
206
207 /* create a random route (lol) */
208 memset(&voice, 0, sizeof(voice));
209 voice.route = &graph->nodes[0].event;
210 voice.count = 1;
211 instrument.voices[0] = voice;
212 instrument.count = 1;
213
214 /* mark it (...) */
215 app.instruments[0].voices[0].route[0].pitch = 42;
216 app.instruments[0].voices[0].route[0].duration = 42000;
217
218 /* init jack */
219 jack.client = jack_client_open(PACKAGE_NAME, JackNullOption, NULL);
220 if (jack.client == NULL) {
221 error("could not connect to jackd");
222 exit(EXIT_FAILURE);
223 }
224
225 err = jack_set_process_callback(jack.client, jack_process_callback, &app);
226
227 if (err) {
228 error("could not set jack process callback");
229 exit(EXIT_FAILURE);
230 }
231
232 err = jack_set_sync_callback(jack.client, jack_sync_callback, &app);
233
234 if (err) {
235 error("could not set jack sync callback");
236 exit(EXIT_FAILURE);
237 }
238
239 jack_on_shutdown(jack.client, jack_shutdown, &app);
240
241 /* allocate one jack port per instrument (midi outs) */
242 for (i = 0; i < app.count; i++) {
243 char name[32];
244 snprintf(name, 32, "out %d", i);
245 app.instruments[i].out = jack_port_register(jack.client, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
246 if (app.instruments[i].out == NULL) {
247 error("could not register a jack midi out port");
248 exit(EXIT_FAILURE);
249 }
250 }
251
252 /* activate jack */
253 if (jack_activate(jack.client)) {
254 error("could not activate jack client");
255 exit(EXIT_FAILURE);
256 }
257
258
259 fprintf(stderr, "==========\n");
260 /* start playing (event loop) */
261 sleep(60);
262 fprintf(stderr, "==========\n");
263
264 /* close jack */
265 jack_client_close (jack.client);
266
267 /* exit */
268 graph_destroy(graph);
269
270 exit(EXIT_SUCCESS);
271 }

  ViewVC Help
Powered by ViewVC 1.1.26