make midimap obey channels
[galan.git] / plugins / libsndfile_in.c
bloba5a2499b0b2bb879df1d1c0a732d305d4eaf43e3
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 "comp.h"
29 #include "control.h"
30 #include "gencomp.h"
31 #include "msgbox.h"
33 #include "sndfile.h"
34 #ifdef HAVE_AUDIOFILE_H
35 #include <audiofile.h>
36 #endif
38 #define GENERATOR_CLASS_NAME "voice"
39 #define GENERATOR_CLASS_PATH "Sources/Sampled Voice (libsndfile)"
41 typedef struct Data {
42 char *filename;
43 SAMPLE *sample;
44 int channels;
45 int frames;
46 gboolean store_sample;
47 } Data;
49 PRIVATE int init_instance(Generator *g) {
50 Data *data = safe_malloc(sizeof(Data));
51 g->data = data;
53 data->filename = NULL;
54 data->sample = NULL;
55 data->frames = 0;
56 data->channels = 1;
57 data->store_sample = TRUE;
59 return 1;
62 PRIVATE void destroy_instance(Generator *g) {
63 Data *data = g->data;
65 if (data->filename != NULL)
66 free(data->filename);
68 if (data->sample != NULL)
69 free(data->sample);
71 free(g->data);
74 PRIVATE gboolean try_load(Generator *g, const char *filename, gboolean verbose) {
75 Data *data = g->data;
76 SAMPLE *inbuf;
77 SAMPLE *old_buf;
78 gboolean success = FALSE;
79 /* For RAW loading: */
80 SNDFILE *f = NULL;
81 SF_INFO sfi;
82 //long pos;
83 /* For audiofile loading: */
85 f = sf_open( filename, SFM_READ, &sfi );
87 success = (f != NULL);
89 if (!success) {
90 if (verbose)
91 popup_msgbox("Load Error", MSGBOX_OK, 0, MSGBOX_OK,
92 "Could not open audio file %s", filename);
93 return FALSE;
96 inbuf = malloc(sizeof(SAMPLE) * sfi.frames * sfi.channels);
98 if (inbuf == NULL) {
99 if (verbose)
100 popup_msgbox("Memory Error", MSGBOX_OK, 0, MSGBOX_OK,
101 "Could not allocate enough memory to store the sample.");
102 sf_close( f );
103 return FALSE;
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;
118 // TODO: add lock.
119 if ( old_buf != NULL)
120 safe_free(old_buf);
122 return TRUE;
125 PRIVATE void unpickle_instance(Generator *g, ObjectStoreItem *item, ObjectStore *db) {
126 Data *data = safe_malloc(sizeof(Data));
127 int i, len;
128 gint16 *buf;
129 gint32 binarylength;
131 g->data = 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);
138 data->sample = NULL;
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);
164 int i;
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));
174 free(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;
186 int len, sil;
187 int i;
189 if (data->frames == 0 || offset >= data->frames)
190 return FALSE;
192 len = MIN(MAX(data->frames - offset, 0), buflen);
195 if (len > 0)
196 for( i=0; i<len; i++ )
197 buf[i] = data->sample[ (offset+i) * (data->channels) + coffset ];
199 sil = buflen - len;
200 memset(&buf[len], 0, sil * sizeof(SAMPLE));
201 return TRUE;
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 )
215 return FALSE;
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 )
225 return FALSE;
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 )
235 return FALSE;
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 !!!" );
245 return;
248 // TODO: make RT safe.
249 if( try_load( g, event->d.string, FALSE ) ) {
250 if( data->filename )
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"));
282 if (data->filename)
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);
291 gtk_widget_show(fs);
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);
312 gtk_widget_show(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);
318 gtk_widget_show(hb);
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 } } },
345 { NULL, }
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) {
360 setup_class();