fix rules for optional plugins.
[galan.git] / src / jack.c
blob9f707ebd492b4e1d51c869cbcb9f2b05931a5f64
1 /* gAlan - Graphical Audio Language
2 * Copyright (C) 1999 Tony Garnock-Jones
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
23 #include <gdk/gdk.h>
24 #include <gtk/gtk.h>
26 #include "global.h"
27 #include "generator.h"
28 #include "control.h"
29 #include "msgbox.h"
31 #include "galan_jack.h"
32 #include "galan_lash.h"
34 #include <jack/jack.h>
35 #ifdef HAVE_JACKMIDI_H
36 #include <jack/midiport.h>
37 #endif
40 PRIVATE jack_client_t *jack_client = NULL;
42 PRIVATE jack_port_t *midi_control_port = NULL;
44 PRIVATE AClock *jack_clock = NULL;
46 PRIVATE GStaticMutex transport_clocks_mutex = G_STATIC_MUTEX_INIT;
47 PRIVATE GStaticMutex jack_process_callbacks_mutex = G_STATIC_MUTEX_INIT;
48 PRIVATE GList *transport_clocks = NULL;
49 PRIVATE GList *jack_process_callbacks = NULL;
51 PRIVATE SAMPLETIME jack_timestamp = 0;
53 PRIVATE Control *midi_map[128*16];
54 PRIVATE Control *midilearn_target = NULL;
55 PRIVATE int midilearn_CC = 0;
57 // Registering Process Callbacks (used for midi ports)
59 typedef struct jack_process_callback_t {
60 Generator *g;
61 jack_process_handler_t handler;
62 } jack_process_callback_t;
64 PUBLIC void galan_jack_register_process_handler( Generator *g, jack_process_handler_t handler ) {
65 jack_process_callback_t *new_cb = safe_malloc( sizeof( jack_process_callback_t ) );
66 new_cb->g = g;
67 new_cb->handler = handler;
68 jack_process_callbacks = g_list_append( jack_process_callbacks, new_cb );
71 PRIVATE gint jack_process_callback_cmp(jack_process_callback_t *a, jack_process_callback_t *b) {
72 return !((a->g == b->g) && (a->handler == b->handler));
75 PUBLIC void galan_jack_deregister_process_handler(Generator *g, jack_process_handler_t func) {
76 jack_process_callback_t jpc;
77 GList *link;
79 g_static_mutex_lock( &jack_process_callbacks_mutex );
80 jpc.g = g;
81 jpc.handler = func;
82 link = g_list_find_custom(jack_process_callbacks, &jpc, (GCompareFunc) jack_process_callback_cmp );
84 if (link != NULL) {
85 free(link->data);
86 link->data = NULL;
87 jack_process_callbacks = g_list_remove_link(jack_process_callbacks, link);
89 g_static_mutex_unlock( &jack_process_callbacks_mutex );
93 // Registering of transport callbacks.
95 typedef struct transport_frame_event_t {
96 Generator *g;
97 transport_frame_event_handler_t handler;
98 } transport_frame_event_t;
100 PRIVATE gint transport_event_handler_cmp(transport_frame_event_t *a, transport_frame_event_t *b) {
101 return !((a->g == b->g) && (a->handler == b->handler));
104 PUBLIC void galan_jack_register_transport_clock( Generator *g, transport_frame_event_handler_t handler ) {
105 transport_frame_event_t *new_cb = safe_malloc( sizeof( transport_frame_event_t ) );
106 new_cb->g = g;
107 new_cb->handler = handler;
108 transport_clocks = g_list_append( transport_clocks, new_cb );
111 PUBLIC void galan_jack_deregister_transport_clock( Generator *g, transport_frame_event_handler_t handler ) {
113 transport_frame_event_t jpc;
114 GList *link;
116 g_static_mutex_lock( &transport_clocks_mutex );
117 jpc.g = g;
118 jpc.handler = handler;
119 link = g_list_find_custom(transport_clocks, &jpc, (GCompareFunc) transport_event_handler_cmp );
121 if (link != NULL) {
122 transport_clocks = g_list_remove_link( transport_clocks, link );
123 free(link->data);
124 link->data = NULL;
126 g_static_mutex_unlock( &transport_clocks_mutex );
130 // Midi Learn
132 PUBLIC void midilearn_set_target_control( Control *c ) {
133 midilearn_target = c;
136 PUBLIC void midilearn_remove_control( Control *c ) {
137 int i;
138 for( i=0; i<(128*16); i++ ) {
139 if( midi_map[i] == c ) {
140 midi_map[i] = NULL;
145 PUBLIC int midilearn_check_result( void ) {
146 if( midilearn_target != NULL )
147 return -1;
149 return midilearn_CC;
152 PUBLIC ObjectStoreDatum *midi_map_pickle(ObjectStore *db) {
153 ObjectStoreDatum *result = objectstore_datum_new_array(128*16);
154 int i;
156 for (i = 0; i < (128*16); i++) {
157 if( midi_map[i] )
158 objectstore_datum_array_set(result, i, objectstore_datum_new_object(control_pickle(midi_map[i], db)));
159 else
160 objectstore_datum_array_set( result, i, NULL );
163 return result;
166 PUBLIC void unpickle_midi_map_array(ObjectStoreDatum *array, ObjectStore *db) {
167 int i, len;
168 len = objectstore_datum_array_length(array);
169 if( len > 128*16 ) {
170 printf( "Error midi_map len wrong !!!" );
171 return;
174 for (i = 0; i < len; i++) {
175 ObjectStoreDatum *elt = objectstore_datum_array_get(array, i);
176 ObjectStoreItem *item = objectstore_get_item_by_key(db, objectstore_datum_object_key(elt));
177 if( item )
178 midi_map[i] = control_unpickle(item);
181 // Helpers.
183 PUBLIC SAMPLETIME galan_jack_get_timestamp( void ) {
184 return jack_timestamp;
187 PUBLIC jack_client_t *galan_jack_get_client(void) {
188 return jack_client;
192 PRIVATE void process_midi_control_port( jack_nframes_t nframes ) {
194 int i;
195 void *port_buffer = jack_port_get_buffer( midi_control_port, nframes );
196 jack_nframes_t num_jackevents = jack_midi_get_event_count( port_buffer );
197 jack_midi_event_t jackevent;
199 for( i=0; i<num_jackevents; i++ ) {
200 if( jack_midi_event_get( &jackevent, port_buffer, i ) != 0 )
201 break;
203 if( (jackevent.buffer[0] & 0xf0) == 0xb0 ) {
204 int CC = jackevent.buffer[1];
205 int CH = jackevent.buffer[0] & 0x0f;
207 if( CC>=128 )
208 continue;
210 if( midilearn_target ) {
211 midi_map[CC+CH*128] = midilearn_target;
212 midilearn_target = NULL;
213 } else if ( midi_map[CC+CH*128] != NULL ) {
214 // midi mapped.
216 Control *c = midi_map[CC+CH*128];
217 if( c != NULL ) {
218 // XXX: need to lock control here.
219 // and send out the data.
220 gdouble rng = c->max - c->min;
221 gdouble cc = jackevent.buffer[2];
222 gdouble val = c->min + rng * cc/127.0;
224 control_emit( c, val );
230 // Process_CB
232 PRIVATE int process_callback( jack_nframes_t nframes, void *data ) {
234 jack_timestamp = gen_get_sampletime();
236 process_midi_control_port( nframes );
238 if( g_static_mutex_trylock( &transport_clocks_mutex ) )
240 if( transport_clocks ) {
241 //jack_transport_info_t trans_info;
242 jack_position_t jack_trans_pos;
243 jack_transport_state_t jack_trans_state;
244 GList *l;
246 jack_trans_state = jack_transport_query( jack_client, &jack_trans_pos );
248 if( jack_trans_state == JackTransportRolling ) {
249 double bpm;
250 if( jack_trans_pos.valid & JackPositionBBT ) {
251 bpm = jack_trans_pos.beats_per_minute;
252 } else {
253 bpm = 120.0;
256 for( l = transport_clocks; l; l = g_list_next( l ) ) {
257 transport_frame_event_t *cb = l->data;
258 cb->handler( cb->g, jack_trans_pos.frame, nframes, bpm );
262 g_static_mutex_unlock( &transport_clocks_mutex );
265 if( g_static_mutex_trylock( &jack_process_callbacks_mutex ) )
267 if( jack_process_callbacks ) {
268 GList *l;
269 for( l = jack_process_callbacks; l; l = g_list_next( l ) ) {
270 jack_process_callback_t *cb = l->data;
271 cb->handler( cb->g, nframes );
274 g_static_mutex_unlock( &jack_process_callbacks_mutex );
276 gen_clock_mainloop_have_remaining( nframes );
278 return 0;
281 PRIVATE void jack_shutdown (void *arg) {
282 g_print( "jack exited :(\n" );
285 PRIVATE void clock_handler(AClock *clock, AClockReason reason) {
287 switch (reason) {
288 case CLOCK_DISABLE:
289 jack_deactivate( jack_client );
290 break;
292 case CLOCK_ENABLE:
293 jack_set_process_callback( jack_client, (JackProcessCallback) process_callback, NULL );
294 jack_on_shutdown (jack_client, jack_shutdown, 0);
296 jack_activate( jack_client );
298 lash_event_t *event;
299 if( lash_enabled( galan_lash_get_client() ) ) {
300 event = lash_event_new_with_type(LASH_Jack_Client_Name);
301 lash_event_set_string(event, jack_get_client_name( jack_client ) );
302 lash_send_event( galan_lash_get_client(), event);
304 break;
306 default:
307 g_message("Unreachable code reached (jack_output)... reason = %d", reason);
308 break;
313 // Init/done
315 PUBLIC void init_jack(void) {
317 int i;
318 jack_client = jack_client_open( "galan", 0, NULL );
319 if (jack_client == NULL) {
320 popup_msgbox("Error", MSGBOX_OK, 120000, MSGBOX_OK,
321 "Could not open Jack Client");
322 exit(10);
324 midi_control_port = jack_port_register ( jack_client, "control", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
325 for(i=0; i<(128*16); i++ ) {
326 midi_map[i] = NULL;
330 PUBLIC void run_jack(void) {
331 jack_clock = gen_register_clock(NULL, "Jack Clock", clock_handler);
332 gen_select_clock(jack_clock);
335 PUBLIC void done_jack(void) {
336 jack_deactivate( jack_client );
337 jack_client_close( jack_client );