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
27 #include "generator.h"
34 #ifdef HAVE_AUDIOFILE_H
35 #include <audiofile.h>
38 #define GENERATOR_CLASS_NAME "voice"
39 #define GENERATOR_CLASS_PATH "Sources/Sampled Voice (libsndfile)"
46 gboolean store_sample
;
49 PRIVATE
int init_instance(Generator
*g
) {
50 Data
*data
= safe_malloc(sizeof(Data
));
53 data
->filename
= NULL
;
57 data
->store_sample
= TRUE
;
62 PRIVATE
void destroy_instance(Generator
*g
) {
65 if (data
->filename
!= NULL
)
68 if (data
->sample
!= NULL
)
74 PRIVATE gboolean
try_load(Generator
*g
, const char *filename
, gboolean verbose
) {
78 gboolean success
= FALSE
;
79 /* For RAW loading: */
83 /* For audiofile loading: */
85 f
= sf_open( filename
, SFM_READ
, &sfi
);
87 success
= (f
!= NULL
);
91 popup_msgbox("Load Error", MSGBOX_OK
, 0, MSGBOX_OK
,
92 "Could not open audio file %s", filename
);
96 inbuf
= malloc(sizeof(SAMPLE
) * sfi
.frames
* sfi
.channels
);
100 popup_msgbox("Memory Error", MSGBOX_OK
, 0, MSGBOX_OK
,
101 "Could not allocate enough memory to store the sample.");
106 // XXX: if SAMPLE changes use another function.
107 // if( sf_readf_double( f, inbuf, sfi.frames ) != sfi.frames )
108 if( sf_readf_float( f
, inbuf
, sfi
.frames
) != sfi
.frames
)
109 g_print( "did not read all data !!!\n" );
111 old_buf
= data
->sample
;
114 data
->frames
= sfi
.frames
;
115 data
->channels
= sfi
.channels
;
116 data
->sample
= inbuf
;
119 if ( old_buf
!= NULL
)
125 PRIVATE
void unpickle_instance(Generator
*g
, ObjectStoreItem
*item
, ObjectStore
*db
) {
126 Data
*data
= safe_malloc(sizeof(Data
));
133 data
->channels
= objectstore_item_get_integer( item
, "voice_channels", 1 );
134 data
->filename
= objectstore_item_get_string(item
, "voice_filename", NULL
);
135 data
->frames
= ( len
= objectstore_item_get_integer(item
, "voice_length", 0) ) / data
->channels
;
136 binarylength
= objectstore_item_get_binary(item
, "voice_sample", (void **) &buf
);
137 data
->store_sample
= objectstore_item_get_integer(item
, "voice_store_sample", 1);
140 if (data
->filename
!= NULL
)
141 data
->filename
= safe_string_dup(data
->filename
);
143 if (binarylength
!= -1) {
144 data
->sample
= safe_malloc(sizeof(SAMPLE
) * len
);
145 for (i
= 0; i
< len
; i
++)
146 data
->sample
[i
] = ((gint16
) g_ntohs(buf
[i
])) / 32768.0;
147 } else if (data
->filename
!= NULL
) {
148 try_load(g
, data
->filename
, FALSE
);
152 PRIVATE
void pickle_instance(Generator
*g
, ObjectStoreItem
*item
, ObjectStore
*db
) {
153 Data
*data
= g
->data
;
155 objectstore_item_set_integer(item
, "voice_bypass_libaudiofile", 0);
156 objectstore_item_set_integer(item
, "voice_store_sample", data
->store_sample
);
157 if (data
->filename
!= NULL
)
158 objectstore_item_set_string(item
, "voice_filename", data
->filename
);
159 objectstore_item_set_integer(item
, "voice_channels", data
->channels
);
161 if (data
->store_sample
) {
162 int bytelength
= sizeof(gint16
) * data
->frames
* data
->channels
;
163 gint16
*buf
= safe_malloc(bytelength
);
166 objectstore_item_set_integer(item
, "voice_length", data
->frames
* data
->channels
);
168 for (i
= 0; i
< (data
->frames
* data
->channels
); i
++)
169 buf
[i
] = g_htons(MAX(-32768, MIN(32767, 32768 * data
->sample
[i
])));
171 objectstore_item_set(item
, "voice_sample",
172 objectstore_datum_new_binary(bytelength
, (void *) buf
));
178 PRIVATE SAMPLETIME
output_range(Generator
*g
, OutputSignalDescriptor
*sig
) {
179 Data
*data
= g
->data
;
180 return data
->frames
/ data
->channels
;
183 PRIVATE gboolean
output_generator(Generator
*g
, OutputSignalDescriptor
*sig
,
184 SAMPLETIME offset
, SAMPLE
*buf
, int buflen
, int coffset
) {
185 Data
*data
= g
->data
;
189 if (data
->frames
== 0 || offset
>= data
->frames
)
192 len
= MIN(MAX(data
->frames
- offset
, 0), buflen
);
196 for( i
=0; i
<len
; i
++ )
197 buf
[i
] = data
->sample
[ (offset
+i
) * (data
->channels
) + coffset
];
200 memset(&buf
[len
], 0, sil
* sizeof(SAMPLE
));
204 PRIVATE gboolean
output_generator_ch0(Generator
*g
, OutputSignalDescriptor
*sig
,
205 SAMPLETIME offset
, SAMPLE
*buf
, int buflen
) {
207 return output_generator( g
,sig
,offset
,buf
,buflen
,0);
210 PRIVATE gboolean
output_generator_ch1(Generator
*g
, OutputSignalDescriptor
*sig
,
211 SAMPLETIME offset
, SAMPLE
*buf
, int buflen
) {
213 Data
*data
= g
->data
;
214 if( data
->channels
< 2 )
217 return output_generator( g
,sig
,offset
,buf
,buflen
,1);
220 PRIVATE gboolean
output_generator_ch2(Generator
*g
, OutputSignalDescriptor
*sig
,
221 SAMPLETIME offset
, SAMPLE
*buf
, int buflen
) {
223 Data
*data
= g
->data
;
224 if( data
->channels
< 3 )
227 return output_generator( g
,sig
,offset
,buf
,buflen
,2);
230 PRIVATE gboolean
output_generator_ch3(Generator
*g
, OutputSignalDescriptor
*sig
,
231 SAMPLETIME offset
, SAMPLE
*buf
, int buflen
) {
233 Data
*data
= g
->data
;
234 if( data
->channels
< 4 )
237 return output_generator( g
,sig
,offset
,buf
,buflen
,3);
240 PRIVATE
void evt_name_handler( Generator
*g
, AEvent
*event
) {
242 Data
*data
= g
->data
;
243 if( event
->kind
!= AE_STRING
) {
244 g_warning( "not a string event when setting name !!!" );
248 // TODO: make RT safe.
249 if( try_load( g
, event
->d
.string
, FALSE
) ) {
251 g_free( data
->filename
);
252 data
->filename
= safe_string_dup( event
->d
.string
);
257 PRIVATE
void load_new_sample(GtkWidget
*widget
, GtkWidget
*fs
) {
258 Generator
*g
= gtk_object_get_data(GTK_OBJECT(fs
), "Generator");
259 GtkWidget
*label
= gtk_object_get_data(GTK_OBJECT(fs
), "FilenameLabel");
260 Data
*data
= g
->data
;
261 const char *filename
= gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs
));
263 if (try_load(g
, filename
, TRUE
)) {
264 if (data
->filename
!= NULL
)
265 free(data
->filename
);
267 data
->filename
= safe_string_dup(filename
);
268 gtk_label_set_text(GTK_LABEL(label
), data
->filename
);
270 gtk_widget_destroy(fs
); /* %%% should this be gtk_widget_hide? uber-paranoia */
274 PRIVATE
void choose_clicked(GtkWidget
*choose_button
, Generator
*g
) {
275 GtkWidget
*fs
= gtk_file_selection_new("Open Sample File");
276 Data
*data
= g
->data
;
278 gtk_object_set_data(GTK_OBJECT(fs
), "Generator", g
);
279 gtk_object_set_data(GTK_OBJECT(fs
), "FilenameLabel",
280 gtk_object_get_data(GTK_OBJECT(choose_button
), "FilenameLabel"));
283 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs
), data
->filename
);
285 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->ok_button
), "clicked",
286 GTK_SIGNAL_FUNC(load_new_sample
), fs
);
287 gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->cancel_button
), "clicked",
288 GTK_SIGNAL_FUNC(gtk_widget_destroy
), GTK_OBJECT(fs
));
290 gtk_window_set_modal(GTK_WINDOW(fs
), TRUE
);
294 PRIVATE
void reload_clicked(GtkWidget
*choose_button
, Generator
*g
) {
295 Data
*data
= g
->data
;
297 if (data
->filename
!= NULL
)
298 try_load(g
, data
->filename
, TRUE
);
301 PRIVATE
void propgen(Component
*c
, Generator
*g
) {
302 Data
*data
= g
->data
;
303 GtkWidget
*vb
= gtk_vbox_new(FALSE
, 5);
304 GtkWidget
*hb
= gtk_hbox_new(TRUE
, 5);
305 GtkWidget
*frame
= gtk_frame_new("Sample File");
306 GtkWidget
*label
= gtk_label_new(data
->filename
? data
->filename
: "<none>");
307 GtkWidget
*reload_button
= gtk_button_new_with_label("Reload");
308 GtkWidget
*choose_button
= gtk_button_new_with_label("Choose File...");
309 GtkWidget
*save_toggle
= gtk_check_button_new_with_label("Save sample with output");
311 gtk_container_add(GTK_CONTAINER(frame
), vb
);
314 gtk_box_pack_start(GTK_BOX(vb
), label
, TRUE
, TRUE
, 0);
315 gtk_widget_show(label
);
317 gtk_box_pack_start(GTK_BOX(vb
), hb
, TRUE
, TRUE
, 0);
320 gtk_box_pack_start(GTK_BOX(vb
), save_toggle
, TRUE
, TRUE
, 0);
321 gtk_widget_show(save_toggle
);
322 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(save_toggle
), data
->store_sample
);
324 gtk_box_pack_start(GTK_BOX(hb
), reload_button
, TRUE
, TRUE
, 0);
325 gtk_widget_show(reload_button
);
326 gtk_box_pack_start(GTK_BOX(hb
), choose_button
, TRUE
, TRUE
, 0);
327 gtk_widget_show(choose_button
);
329 gtk_signal_connect(GTK_OBJECT(reload_button
), "clicked",
330 GTK_SIGNAL_FUNC(reload_clicked
), g
);
331 gtk_signal_connect(GTK_OBJECT(choose_button
), "clicked",
332 GTK_SIGNAL_FUNC(choose_clicked
), g
);
333 gtk_object_set_data(GTK_OBJECT(choose_button
), "FilenameLabel", label
);
335 popup_dialog("Properties", MSGBOX_DISMISS
, 0, MSGBOX_DISMISS
, frame
, NULL
, 0);
337 data
->store_sample
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(save_toggle
));
340 PRIVATE OutputSignalDescriptor output_sigs
[] = {
341 { "Channel 0", SIG_FLAG_RANDOMACCESS
, { NULL
, { output_range
, output_generator_ch0
} } },
342 { "Channel 1", SIG_FLAG_RANDOMACCESS
, { NULL
, { output_range
, output_generator_ch1
} } },
343 { "Channel 2", SIG_FLAG_RANDOMACCESS
, { NULL
, { output_range
, output_generator_ch2
} } },
344 { "Channel 3", SIG_FLAG_RANDOMACCESS
, { NULL
, { output_range
, output_generator_ch3
} } },
348 PRIVATE
void setup_class(void) {
349 GeneratorClass
*k
= gen_new_generatorclass(GENERATOR_CLASS_NAME
, TRUE
, 1, 0,
350 NULL
, output_sigs
, NULL
,
351 init_instance
, destroy_instance
,
352 unpickle_instance
, pickle_instance
);
354 gen_configure_event_input(k
, 0, "Filename", evt_name_handler
);
356 gencomp_register_generatorclass(k
, TRUE
, GENERATOR_CLASS_PATH
, NULL
, propgen
);
359 PUBLIC
void init_plugin(void) {