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.) */
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)
31 * - display n*SAMPLE_RATE samples
34 * - you know what a hardware scope can do :-)
48 #include "generator.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"
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
78 /* state, to be pickled, unpickled */
80 SAMPLE ysize
; /* sizeof(intbuf) = ysize * SAMPLE_RATE */
83 gint32 loop_start
, loop_end
;
85 /* transient the table size is yscale */
91 PRIVATE
void setup_tables(void) {
92 /* Put any plugin-wide initialisation here. */
95 PRIVATE
void realtime_handler(Generator
*g
, AEvent
*event
) {
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) )
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 );
133 data
->loop_start
= 0;
134 data
->loop_end
= intbufbytes
-1;
135 gen_update_controls( g
, -1 );
145 g_warning("scope module doesn't care for events of kind %d.", event
->kind
);
151 PRIVATE gboolean
init_instance(Generator
*g
) {
152 /* TODO: need to allocate the intbuf of size yscale */
153 Data
*data
= safe_malloc(sizeof(Data
));
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
);
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
);
182 PRIVATE
void unpickle_instance(Generator
*g
, ObjectStoreItem
*item
, ObjectStore
*db
) {
184 Data
*data
= safe_malloc(sizeof(Data
));
185 gint32 binarylength
, i
;
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;
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
;
241 if (duration
== 0 || offset
>= duration
)
245 len
= MIN(MAX(duration
- offset
, 0), buflen
);
247 memcpy(buf
, &data
->samplebuf
[offset
+data
->loop_start
], len
* sizeof(SAMPLE
));
250 memset(&buf
[len
], 0, sil
* sizeof(SAMPLE
));
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
) {
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
) {
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
;
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
369 Data
*data
= g
->data
;
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));
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..
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));
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
},
494 PRIVATE OutputSignalDescriptor output_sigs
[] = {
495 { "Samples", SIG_FLAG_RANDOMACCESS
, { NULL
, { output_range
, output_generator
} } },
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
,
529 PUBLIC
void init_plugin(void) {