missing commit in generator.h
[galan.git] / plugins / libmidi_seq_clock.c
bloba4b353b9a87bb5f0a8beb14c788505d72a1a3c91
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>
22 #include <stddef.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
29 #include <sys/ioctl.h>
30 #include <sys/soundcard.h>
32 #include <gdk/gdk.h>
33 #include <gtk/gtk.h>
35 #include "global.h"
36 #include "generator.h"
37 #include "comp.h"
38 #include "control.h"
39 #include "gencomp.h"
40 #include "msgbox.h"
42 #define GENERATOR_CLASS_NAME "midiseqclock"
43 #define GENERATOR_CLASS_PATH "Misc/MIDI Sequencer Clock"
45 #define MIDI_BUFSIZE 8
47 /*
48 * Here is the Data....
52 enum EVT_INPUTS {
53 NUM_EVENT_INPUTS = 0
56 enum EVT_OUTPUTS {
57 EVT_CLOCK = 0,
58 EVT_START,
59 EVT_CHANNEL,
60 EVT_NOTE,
61 EVT_VELOCITY,
62 EVT_PROGAMCHANGE,
63 NUM_EVENT_OUTPUTS
66 typedef struct Data {
67 gint fd;
68 gint input_tag;
69 SAMPLETIME miditime_offset;
70 SAMPLETIME gentime_offset;
71 SAMPLETIME last_timestamp;
72 gint midibytestocome, midibufpos;
73 unsigned char midibuffer[MIDI_BUFSIZE];
74 SAMPLETIME buffer_timestamp;
75 unsigned char laststatus;
76 } Data;
80 * This is the input callback....
81 * Seems to bo ok for now..
84 PRIVATE int get_bytes_to_come( unsigned char midistatus ) {
86 switch( midistatus & 0xf0 ) {
88 case 0x80:
89 case 0x90:
90 case 0xa0:
91 case 0xb0:
92 case 0xe0:
93 return 2;
94 case 0xc0:
95 case 0xd0:
96 return 1;
98 default:
99 return 0;
103 PRIVATE void execute_midi_command( Generator *g ) {
105 AEvent event;
106 Data *data = g->data;
107 int channel = data->laststatus & 0x0f;
109 g_print( "Executing MIDI Command %d...\n" , (int) data->laststatus );
110 switch( data->laststatus & 0xf0 ) {
111 case 0x90:
113 // now the note is in data->midibuffer[0] and the velocity is in [1]
115 //g_print( "lasttimestamp=%d, gen=%d, diff=%d (%fsec)\n", data->last_timestamp, gen_get_sampletime(), data->last_timestamp - gen_get_sampletime(), ((gdouble)(data->last_timestamp - gen_get_sampletime())) / SAMPLE_RATE );
116 gen_init_aevent( &event, AE_NUMBER, NULL, 0, NULL, 0, data->last_timestamp );
118 event.d.number = channel;
119 gen_send_events(g, EVT_CHANNEL, -1, &event);
121 //g_print( "(%x,%x)\n", data->midibuffer[0], data->midibuffer[1] );
122 event.d.number = data->midibuffer[0];
123 gen_send_events(g, EVT_NOTE, -1, &event);
125 event.d.number = data->midibuffer[1];
126 gen_send_events(g, EVT_VELOCITY, -1, &event);
128 break;
131 case 0xc0:
133 gen_init_aevent( &event, AE_NUMBER, NULL, 0, NULL, 0, data->last_timestamp );
135 event.d.number = channel;
136 gen_send_events(g, EVT_CHANNEL, -1, &event);
138 //g_print( "(%x,%x)\n", data->midibuffer[0], data->midibuffer[1] );
139 event.d.number = data->midibuffer[0];
140 gen_send_events(g, EVT_PROGAMCHANGE, -1, &event);
148 PRIVATE void input_callback( Generator *g, gint source, GdkInputCondition condition ) {
150 Data *data = g->data;
151 unsigned char midievent[4];
152 AEvent event;
153 int l,i;
155 l = read( source, &midievent, 4 );
157 for( i=0; i<l; i+=4 ) {
158 //g_print( "%d midiev: %d, %x\n", i, (int) midievent[i], *((int *) &midievent[i]) & 0xffffff00 );
159 switch( midievent[i] ) {
160 case SEQ_WAIT:
161 //g_print( "TMR_WAIT_ABS: %d\n", *((int *) &midievent[i]) >> 8 );
162 if( data->miditime_offset == -1 ) {
163 data->miditime_offset = (*((int *) midievent) >> 8) * SAMPLE_RATE / 100;
164 data->gentime_offset = gen_get_sampletime();
166 data->last_timestamp = (*((int *) &midievent[i]) >> 8) * SAMPLE_RATE / 100
167 - data->miditime_offset + data->gentime_offset;
169 break;
170 case SEQ_MIDIPUTC:
171 switch( midievent[1] & 0xf0 ) {
172 case 0xf0:
173 switch( midievent[1] ) {
174 case 0xf8:
175 gen_init_aevent(&event, AE_NUMBER, NULL, 0, NULL, 0, data->last_timestamp );
176 event.d.number = 1;
177 gen_send_events(g, EVT_CLOCK, -1, &event);
178 break;
180 case 0xfa:
181 gen_init_aevent(&event, AE_NUMBER, NULL, 0, NULL, 0, data->last_timestamp );
182 event.d.number = 1;
183 gen_send_events(g, EVT_START, -1, &event);
184 break;
186 break;
188 case 0xe0:
189 case 0xd0:
190 case 0xc0:
191 case 0xb0:
192 case 0xa0:
193 case 0x80:
194 case 0x90:
195 data->laststatus = midievent[1];
196 data->midibytestocome = get_bytes_to_come( data->laststatus );
197 //g_print( "playevent here\n" );
198 data->midibufpos = 0;
200 break;
202 default:
203 //g_print( "in default... %d ls=%x\n", data->midibytestocome, (int) data->laststatus );
204 if( data->midibytestocome ) {
206 data->midibuffer[data->midibufpos++] = midievent[1];
208 if( (data->midibytestocome--) == 1 ) {
210 // Now there is a midicommand in data->midibuffer
211 // status byte is data->laststatus
213 execute_midi_command( g );
216 } else {
218 // running command.. set bytes_to_come to
219 data->midibytestocome = get_bytes_to_come( data->laststatus ) - 1;
220 data->midibufpos = 0;
222 // Store this byte...
223 data->midibuffer[data->midibufpos++] = midievent[1];
229 break;
236 * Constuctor and Destructor
238 * I have to add a global-property to get /dev/input/js0 from config.
239 * Of course make it configurable in plugin-properties.
241 * then i need asserts... But hey it works now :-)
242 * Instance can be added even if configured for js1 and only js0
243 * available (??? confusing having non working component )
247 PRIVATE int init_instance(Generator *g) {
248 Data *data = safe_malloc(sizeof(Data));
249 g->data = data;
251 data->fd = open( "/dev/sequencer", O_RDWR );
252 if( data->fd > 0 ) {
253 free( data );
254 return 0;
256 data->miditime_offset = -1;
257 data->last_timestamp = gen_get_sampletime();
258 data->midibytestocome = 0;
259 data->laststatus = 0;
261 // ioctl( data->fd, SNDCTL_SEQ_ACTSENSE_ENABLE, 0 );
262 // ioctl( data->fd, SNDCTL_SEQ_TIMING_ENABLE, 0 );
263 // ioctl( data->fd, SNDCTL_SEQ_RT_ENABLE, 0 );
265 data->input_tag = gdk_input_add( data->fd, GDK_INPUT_READ, (GdkInputFunction) input_callback, (gpointer) g );
266 return 1;
269 PRIVATE void destroy_instance(Generator *g) {
270 Data *data = g->data;
272 gdk_input_remove( data->input_tag );
273 close( data->fd );
275 free(g->data);
280 * pickle and unpickle
282 * are straight forward....
286 PRIVATE void unpickle_instance(Generator *g, ObjectStoreItem *item, ObjectStore *db) {
287 Data *data = safe_malloc(sizeof(Data));
288 g->data = data;
290 data->fd = open( "/dev/sequencer", O_RDONLY | O_NONBLOCK );
291 data->input_tag = gdk_input_add( data->fd, GDK_INPUT_READ, (GdkInputFunction) input_callback, g );
293 data->miditime_offset = -1;
294 data->last_timestamp = gen_get_sampletime();
295 data->midibytestocome = 0;
296 data->laststatus = 0;
300 PRIVATE void pickle_instance(Generator *g, ObjectStoreItem *item, ObjectStore *db) {
301 //Data *data = g->data;
305 PRIVATE ControlDescriptor controls[] = {
306 /* { kind, name, min,max,step,page, size,editable, is_dst,queue_number,
307 init,destroy,refresh,refresh_data }, */
308 { CONTROL_KIND_NONE, }
313 * setup Class
315 * much TODO here....
317 * check how many buttons and axes we have...
318 * can i change this dynamicly ???
322 PRIVATE void setup_class(void) {
323 GeneratorClass *k = gen_new_generatorclass(GENERATOR_CLASS_NAME, FALSE, NUM_EVENT_INPUTS, NUM_EVENT_OUTPUTS,
324 NULL, NULL, controls,
325 init_instance, destroy_instance,
326 unpickle_instance, pickle_instance);
328 gen_configure_event_output(k, EVT_CLOCK, "Clock");
329 gen_configure_event_output(k, EVT_START, "Start");
330 gen_configure_event_output(k, EVT_CHANNEL, "Channel");
331 gen_configure_event_output(k, EVT_NOTE, "Note");
332 gen_configure_event_output(k, EVT_VELOCITY, "Velocity");
333 gen_configure_event_output(k, EVT_PROGAMCHANGE, "Program");
334 gencomp_register_generatorclass(k, FALSE, GENERATOR_CLASS_PATH, NULL, NULL);
337 PUBLIC void init_plugin(void) {
338 setup_class();