missing commit in generator.h
[galan.git] / plugins / libsampler.c
blob1500566d304ea4b5b1dc6cca5dff534323fc1406
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 /* Template gAlan plugin file. Please distribute your plugins according to
20 the GNU General Public License! (You don't have to, but I'd prefer it.) */
22 /* yep GPL apllies */
24 /* modified to be a scope plugin... requires changes to galan... but only
25 * because of me being lazy #include "sample-display.c" should do the job..
27 * but because sample display is so powerful i plan to use it for sample input
28 * to... (well.. should be in rart.c for loops)
30 * missing features:
31 * - display n*SAMPLE_RATE samples
32 * - trigger
33 * - resizing
34 * - you know what a hardware scope can do :-)
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <stddef.h>
42 #include <gdk/gdk.h>
43 #include <gtk/gtk.h>
44 #include <gmodule.h>
45 #include <glib.h>
47 #include "global.h"
48 #include "generator.h"
49 #include "comp.h"
50 #include "control.h"
51 #include "gencomp.h"
53 #include "sample-display.h"
55 #define GENERATOR_CLASS_NAME "sampler"
56 #define GENERATOR_CLASS_PATH "Misc/Sampler"
57 #define GENERATOR_CLASS_PIXMAP "template.xpm"
59 #define SIG_INPUT 1
60 #define SIG_OUTPUT 0
62 #define EVT_TRIGGER 0
63 #define EVT_YSCALE 1
64 #define EVT_XSCALE 2
65 #define EVT_LOOP_START 3
66 #define EVT_LOOP_END 4
67 #define EVT_EMIT_BUFFER 5
68 #define EVT_RCV_BUFFER 6
69 #define NUM_EVENT_INPUTS 7
71 #define EVT_LOOP_START_OUT 0
72 #define EVT_LOOP_END_OUT 1
73 #define EVT_BUFFER_OUT 2
74 #define NUM_EVENT_OUTPUTS 3
77 typedef struct Data {
78 /* state, to be pickled, unpickled */
79 gint32 phase;
80 SAMPLE ysize; /* sizeof(intbuf) = ysize * SAMPLE_RATE */
81 SAMPLE xsize;
83 gint32 loop_start, loop_end;
85 /* transient the table size is yscale */
86 gboolean go;
87 gint8 *intbuf;
88 SAMPLE *samplebuf;
89 } Data;
91 PRIVATE void setup_tables(void) {
92 /* Put any plugin-wide initialisation here. */
95 PRIVATE void realtime_handler(Generator *g, AEvent *event) {
97 Data *data = g->data;
99 switch (event->kind)
101 case AE_REALTIME:
103 if( data->go ) {
104 gint32 oldphase;
105 //GList *l;
106 SAMPLE *buf, *bufX;
108 int bufbytes = event->d.integer * sizeof(SAMPLE);
109 int intbufbytes = sizeof(gint8)*(SAMPLE_RATE*data->xsize);
111 buf = g_alloca(bufbytes);
113 if (!gen_read_realtime_input(g, 0, -1, buf, event->d.integer))
114 memset(buf, 0, bufbytes);
117 for( bufX=buf,oldphase = data->phase; (data->phase-oldphase)<event->d.integer && (data->phase < intbufbytes); (data->phase)++,bufX++ )
119 data->intbuf[data->phase]=CLIP_SAMPLE(*bufX * data->ysize)*127;
120 data->samplebuf[data->phase]=*bufX;
123 if( data->phase >= intbufbytes )
125 // for( l=g_list_first(g->controls); l != NULL; l=g_list_next(l) )
126 // {
127 // Control *controlx = l->data;
128 // g_assert( controlx->data != NULL );
129 // sample_display_set_data_8( (SampleDisplay *)controlx->data,
130 // data->intbuf, intbufbytes, TRUE );
131 // sample_display_set_loop( (SampleDisplay *)controlx->data, 0, intbufbytes-1 );
132 // }
133 data->loop_start = 0;
134 data->loop_end = intbufbytes-1;
135 gen_update_controls( g, -1 );
136 data->phase = 0;
137 data->go = FALSE;
141 break;
144 default:
145 g_warning("scope module doesn't care for events of kind %d.", event->kind);
146 break;
151 PRIVATE gboolean init_instance(Generator *g) {
152 /* TODO: need to allocate the intbuf of size yscale */
153 Data *data = safe_malloc(sizeof(Data));
154 g->data = data;
156 data->phase = 0;
157 data->go = FALSE;
158 data->ysize = 1;
159 data->xsize = 0.1;
161 data->loop_start = 0;
162 data->loop_end = data->xsize * SAMPLE_RATE - 1;
163 data->intbuf = safe_malloc( sizeof(gint8)*(SAMPLE_RATE*data->xsize+1));
164 data->samplebuf = safe_malloc( sizeof(SAMPLE)*(SAMPLE_RATE*data->xsize+1));
166 memset( data->intbuf, 0, sizeof(gint8)*(SAMPLE_RATE*data->xsize+1) );
167 memset( data->samplebuf, 0, sizeof(SAMPLE)*(SAMPLE_RATE*data->xsize+1) );
169 gen_register_realtime_fn(g, realtime_handler);
171 return TRUE;
174 PRIVATE void destroy_instance(Generator *g) {
175 gen_deregister_realtime_fn(g, realtime_handler);
176 free(((Data *)(g->data))->intbuf);
177 free(((Data *)(g->data))->samplebuf);
178 free(g->data);
182 PRIVATE void unpickle_instance(Generator *g, ObjectStoreItem *item, ObjectStore *db) {
184 Data *data = safe_malloc(sizeof(Data));
185 gint32 binarylength, i;
186 SAMPLE *samplebuf;
187 g->data = data;
189 data->go = FALSE;
190 data->phase = objectstore_item_get_integer(item, "scope_phase", 0);
191 data->ysize = objectstore_item_get_double(item, "scope_ysize", 1);
192 data->xsize = objectstore_item_get_double(item, "scope_xsize", 0.1);
193 data->loop_start = objectstore_item_get_double( item, "loop_start", 0 );
194 data->loop_end = objectstore_item_get_double( item, "loop_end", data->xsize * SAMPLE_RATE - 1 );
196 data->intbuf = (gint8 *)safe_malloc( sizeof(gint8)*(SAMPLE_RATE*data->xsize+1));
197 data->samplebuf = safe_malloc( sizeof(SAMPLE)*(SAMPLE_RATE*data->xsize+1));
199 binarylength = objectstore_item_get_binary(item, "sample_data", (void **) &samplebuf);
200 if( binarylength > 0 ) {
201 if( (binarylength/sizeof(SAMPLE)) < (data->xsize * SAMPLE_RATE) ) {
202 for( i=0; i<(binarylength/sizeof(SAMPLE)); i++ ) {
203 data->samplebuf[i] = samplebuf[i];
204 data->intbuf[i] = CLIP_SAMPLE(samplebuf[i] * data->ysize) * 127;
206 }else{
207 for( i=0; i<data->xsize * SAMPLE_RATE; i++ ) {
208 data->samplebuf[i] = samplebuf[i];
209 data->intbuf[i] = CLIP_SAMPLE(samplebuf[i] * data->ysize) * 127;
214 gen_register_realtime_fn(g, realtime_handler);
217 PRIVATE void pickle_instance(Generator *g, ObjectStoreItem *item, ObjectStore *db) {
218 Data *data = g->data;
219 objectstore_item_set_integer(item, "scope_phase", data->phase);
220 objectstore_item_set_double(item, "scope_ysize", data->ysize);
221 objectstore_item_set_double(item, "scope_xsize", data->xsize);
222 objectstore_item_set_double(item, "loop_start", data->loop_start);
223 objectstore_item_set_double(item, "loop_end", data->loop_end);
226 objectstore_item_set(item, "sample_data",
227 objectstore_datum_new_binary(data->xsize * SAMPLE_RATE * sizeof(SAMPLE), (void *) data->samplebuf));
230 PRIVATE SAMPLETIME output_range(Generator *g, OutputSignalDescriptor *sig) {
231 Data *data = g->data;
232 return data->loop_end - data->loop_start;
235 PRIVATE gboolean output_generator(Generator *g, OutputSignalDescriptor *sig,
236 SAMPLETIME offset, SAMPLE *buf, int buflen) {
237 Data *data = g->data;
238 int duration = data->loop_end - data->loop_start;
239 int len, sil;
241 if (duration == 0 || offset >= duration)
242 return FALSE;
245 len = MIN(MAX(duration - offset, 0), buflen);
246 if (len > 0)
247 memcpy(buf, &data->samplebuf[offset+data->loop_start], len * sizeof(SAMPLE));
249 sil = buflen - len;
250 memset(&buf[len], 0, sil * sizeof(SAMPLE));
251 return TRUE;
254 PRIVATE void loop_handler( SampleDisplay *s, int start, int end ) {
255 Control *c = gtk_object_get_user_data( GTK_OBJECT( s ) );
256 Data *data = c->g->data;
258 if( data->loop_start != start ) {
259 AEvent event;
260 data->loop_start = start;
262 gen_init_aevent(&event, AE_NUMBER, NULL, 0, NULL, 0, gen_get_sampletime());
263 event.d.number = start;
264 gen_send_events( c->g, EVT_LOOP_START_OUT, -1, &event );
267 if( data->loop_end != end ) {
268 AEvent event;
269 data->loop_end = end;
271 gen_init_aevent(&event, AE_NUMBER, NULL, 0, NULL, 0, gen_get_sampletime());
272 event.d.number = end;
273 gen_send_events( c->g, EVT_LOOP_END_OUT, -1, &event );
277 PRIVATE void loop_selection_handler( GtkWidget *b, Control *c ) {
279 //Data *data = c->g->data;
280 SampleDisplay *sc = c->data;
282 sample_display_set_loop( sc, sc->sel_start, sc->sel_end );
285 PRIVATE void zoom_selection_handler( GtkWidget *b, Control *c ) {
287 //Data *data = c->g->data;
288 SampleDisplay *sc = c->data;
290 sample_display_set_window( sc, sc->sel_start, sc->sel_end );
293 PRIVATE void zoom_out_handler( GtkWidget *b, Control *c ) {
295 Data *data = c->g->data;
296 SampleDisplay *sc = c->data;
298 sample_display_set_window( sc, MAX( 0, sc->win_start - sc->win_length/2 ),
299 MIN( data->xsize * SAMPLE_RATE - 1, sc->win_start + sc->win_length*2 ));
301 PRIVATE void zoom_in_handler( GtkWidget *b, Control *c ) {
303 //Data *data = c->g->data;
304 SampleDisplay *sc = c->data;
306 sample_display_set_window( sc, sc->win_start + sc->win_length/4, sc->win_start + sc->win_length * 0.75 );
308 PRIVATE void init_scope( Control *control ) {
310 GtkWidget *sc, *vb, *hb, *zoom_in, *zoom_out, *set_loop, *sel_loop;
311 Data *data = control->g->data;
312 gint32 intbufbytes = sizeof(gint8) * data->xsize * SAMPLE_RATE;
314 vb=gtk_vbox_new( 0,FALSE );
315 hb=gtk_hbox_new( 0,FALSE );
316 g_assert( vb != NULL );
318 zoom_in = gtk_button_new_with_label( "+" );
319 gtk_signal_connect( GTK_OBJECT( zoom_in ), "clicked", GTK_SIGNAL_FUNC( zoom_in_handler ), control );
320 zoom_out = gtk_button_new_with_label( "-" );
321 gtk_signal_connect( GTK_OBJECT( zoom_out ), "clicked", GTK_SIGNAL_FUNC( zoom_out_handler ), control );
322 sel_loop = gtk_button_new_with_label( "zoom_sel" );
323 gtk_signal_connect( GTK_OBJECT( sel_loop ), "clicked", GTK_SIGNAL_FUNC( zoom_selection_handler ), control );
324 set_loop = gtk_button_new_with_label( "loop" );
325 gtk_signal_connect( GTK_OBJECT( set_loop ), "clicked", GTK_SIGNAL_FUNC( loop_selection_handler ), control );
327 sc = sample_display_new(TRUE);
328 gtk_widget_set_usize( sc, 250, 100 );
329 gtk_object_set_user_data( GTK_OBJECT(sc), control );
331 gtk_signal_connect( GTK_OBJECT( sc ), "loop_changed", GTK_SIGNAL_FUNC( loop_handler ), NULL );
334 gtk_box_pack_start( GTK_BOX( hb ), zoom_in, TRUE, TRUE, 0 );
335 gtk_box_pack_start( GTK_BOX( hb ), zoom_out, TRUE, TRUE, 0 );
336 gtk_box_pack_start( GTK_BOX( hb ), sel_loop, TRUE, TRUE, 0 );
337 gtk_box_pack_start( GTK_BOX( hb ), set_loop, TRUE, TRUE, 0 );
338 gtk_box_pack_start( GTK_BOX( vb ), sc, TRUE, TRUE, 0 );
339 gtk_box_pack_start( GTK_BOX( vb ), hb, TRUE, TRUE, 0 );
341 gtk_widget_show_all( vb );
343 sample_display_set_data_8( SAMPLE_DISPLAY(sc),
344 data->intbuf, intbufbytes, TRUE );
345 sample_display_set_loop( SAMPLE_DISPLAY(sc), data->loop_start, data->loop_end );
347 control->widget = vb;
348 control->data = sc;
351 PRIVATE void done_scope(Control *control) {
354 PRIVATE void refresh_scope(Control *control) {
355 Data *data = control->g->data;
356 int intbufbytes = sizeof(gint8)*(SAMPLE_RATE*data->xsize);
358 sample_display_set_data_8( (SampleDisplay *)control->data,
359 data->intbuf, intbufbytes, TRUE );
361 sample_display_set_loop( (SampleDisplay *)control->data, data->loop_start, data->loop_end );
365 PRIVATE void evt_trigger_handler(Generator *g, AEvent *event) {
366 /* handle incoming events on queue EVT_TRIGGER
367 * set phase=0;
369 Data *data = g->data;
370 data->phase=0;
371 data->go = TRUE;
374 PRIVATE void evt_xscale_handler(Generator *g, AEvent *event) {
375 /* handle incoming events on queue EVT_YSCALE
376 * when yscale changes need to resize buffer
377 * first free, malloc, then be smart
378 * i also drop all data in the buffer. could be better...
379 * lets see if there is demand..
382 Data *data = g->data;
384 if( event->d.number != data->xsize ) {
385 free( data->intbuf );
386 free( data->samplebuf );
388 data->xsize = event->d.number;
389 data->intbuf = (gint8 *)safe_malloc( sizeof(gint8)*(SAMPLE_RATE*data->xsize+1));
390 data->samplebuf = (SAMPLE *)safe_malloc( sizeof(SAMPLE)*(SAMPLE_RATE*data->xsize+1));
391 data->phase = 0;
396 PRIVATE void evt_yscale_handler(Generator *g, AEvent *event) {
397 /* handle incoming events on queue EVT_XSCALE
398 * this only changes XSCALE factor which is only used for
399 * generating the gint8[] so nothing special here
401 Data *data = g->data;
402 data->ysize = event->d.number;
405 PRIVATE void evt_loop_start_handler(Generator *g, AEvent *event) {
406 /* handle incoming events on queue EVT_LOOP_START
407 * this only changes XSCALE factor which is only used for
408 * generating the gint8[] so nothing special here
410 Data *data = g->data;
412 data->loop_start = MAX( 0, event->d.number );
413 //for( l=g_list_first(g->controls); l != NULL; l=g_list_next(l) )
415 // Control *controlx = l->data;
416 // g_assert( controlx->data != NULL );
417 // sample_display_set_loop( (SampleDisplay *)controlx->data, data->loop_start, data->loop_end );
419 gen_update_controls( g, -1 );
420 gen_send_events( g, EVT_LOOP_START_OUT, -1, event );
423 PRIVATE void evt_loop_end_handler(Generator *g, AEvent *event) {
424 /* handle incoming events on queue EVT_LOOP_START
425 * this only changes XSCALE factor which is only used for
426 * generating the gint8[] so nothing special here
428 Data *data = g->data;
430 data->loop_end = MIN( event->d.number, data->xsize * SAMPLE_RATE - 1 );
431 //for( l=g_list_first(g->controls); l != NULL; l=g_list_next(l) )
433 // Control *controlx = l->data;
434 // g_assert( controlx->data != NULL );
435 // sample_display_set_loop( (SampleDisplay *)controlx->data, data->loop_start, data->loop_end );
437 gen_update_controls( g, -1 );
438 gen_send_events( g, EVT_LOOP_END_OUT, -1, event );
441 PRIVATE void evt_emit_buffer_handler(Generator *g, AEvent *event) {
442 Data *data = g->data;
444 gen_init_aevent(event, AE_NUMARRAY, NULL, 0, NULL, 0, event->time);
446 event->d.array.len = data->xsize * SAMPLE_RATE;
447 //g_printf( "hallo %d\n", event->d.array.len );
448 event->d.array.numbers = data->samplebuf;
450 gen_send_events(g, EVT_BUFFER_OUT, -1, event);
451 event->kind = AE_NONE;
454 PRIVATE void evt_receive_buffer_handler(Generator *g, AEvent *event) {
455 /* handle incoming events on queue EVT_YSCALE
456 * when yscale changes need to resize buffer
457 * first free, malloc, then be smart
458 * i also drop all data in the buffer. could be better...
459 * lets see if there is demand..
462 int i;
463 Data *data = g->data;
464 RETURN_UNLESS( event->kind == AE_NUMARRAY );
466 //g_printf( "here %d\n", event->d.array.len );
467 if( (gdouble)event->d.array.len/SAMPLE_RATE != data->xsize) {
468 free( data->intbuf );
469 free( data->samplebuf );
471 data->xsize = (gdouble)event->d.array.len / SAMPLE_RATE ;
472 data->intbuf = (gint8 *)safe_malloc( sizeof(gint8)*(SAMPLE_RATE*data->xsize+1));
473 data->samplebuf = (SAMPLE *)safe_malloc( sizeof(SAMPLE)*(SAMPLE_RATE*data->xsize+1));
474 data->phase = 0;
475 //g_printf( "here %d\n", event->d.array.len );
478 memcpy( data->samplebuf, event->d.array.numbers, event->d.array.len*sizeof( SAMPLE ) );
479 for( i=0; i<event->d.array.len; i++ )
480 data->intbuf[i] = CLIP_SAMPLE(event->d.array.numbers[i]) * 127;
482 data->loop_start = 0;
483 data->loop_end = data->xsize * SAMPLE_RATE - 1;
485 gen_update_controls( g, -1 );
489 PRIVATE InputSignalDescriptor input_sigs[] = {
490 { "Input", SIG_FLAG_REALTIME },
491 { NULL, }
494 PRIVATE OutputSignalDescriptor output_sigs[] = {
495 { "Samples", SIG_FLAG_RANDOMACCESS, { NULL, { output_range, output_generator } } },
496 { NULL, }
499 PRIVATE ControlDescriptor controls[] = {
500 { CONTROL_KIND_USERDEF, "sampledisplay", 0,0,0,0, 0,FALSE, 0,0, init_scope, done_scope, refresh_scope },
501 /* { kind, name, min,max,step,page, size,editable, is_dst,queue_number,
502 init,destroy,refresh,refresh_data }, */
503 { CONTROL_KIND_NONE, }
506 PRIVATE void setup_class(void) {
507 GeneratorClass *k = gen_new_generatorclass(GENERATOR_CLASS_NAME, FALSE,
508 NUM_EVENT_INPUTS, NUM_EVENT_OUTPUTS,
509 input_sigs, output_sigs, controls,
510 init_instance, destroy_instance,
511 unpickle_instance, pickle_instance);
513 gen_configure_event_input(k, EVT_TRIGGER, "Trigger", evt_trigger_handler);
514 gen_configure_event_input(k, EVT_YSCALE, "YSize", evt_yscale_handler);
515 gen_configure_event_input(k, EVT_XSCALE, "XSize", evt_xscale_handler);
516 gen_configure_event_input(k, EVT_LOOP_START, "Loop Start", evt_loop_start_handler);
517 gen_configure_event_input(k, EVT_LOOP_END, "Loop End", evt_loop_end_handler);
518 gen_configure_event_input(k, EVT_EMIT_BUFFER, "Emit Buffer", evt_emit_buffer_handler);
519 gen_configure_event_input(k, EVT_RCV_BUFFER, "Receive Buffer", evt_receive_buffer_handler);
521 gen_configure_event_output(k, EVT_LOOP_START_OUT, "Loop Start Out");
522 gen_configure_event_output(k, EVT_LOOP_END_OUT, "Loop End Out");
523 gen_configure_event_output(k, EVT_BUFFER_OUT, "Buffer Out");
525 gencomp_register_generatorclass(k, FALSE, GENERATOR_CLASS_PATH,
526 NULL, NULL);
529 PUBLIC void init_plugin(void) {
530 setup_tables();
531 setup_class();