root/sweep/trunk/src/file_sndfile1.c

Revision 691, 23.4 kB (checked in by erikd, 2 years ago)

Remove needless #defines of buffer lengths.

Code had many instances of:

#undef BUF_LEN
#define BUF_LEN 64
char buf[BUF_LEN];
snprintf (buf, BUF_LEN, ....);

which can be replaced with:

char buf[64];
snprintf (buf, sizeof (buf), ....);

which is far cleaner and more difficult to get wrong.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Sweep, a sound wave editor.
3  *
4  * Copyright (C) 2000 Conrad Parker
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <errno.h>
30
31 #include <pthread.h>
32
33 #include <sndfile.h>
34
35 #define BUFFER_LEN 1024
36
37 #include <glib.h>
38 #include <gtk/gtk.h>
39
40 #include <sweep/sweep_i18n.h>
41 #include <sweep/sweep_types.h>
42 #include <sweep/sweep_typeconvert.h>
43 #include <sweep/sweep_sample.h>
44 #include <sweep/sweep_undo.h>
45 #include <sweep/sweep_sounddata.h>
46
47 #include "sample.h"
48 #include "file_dialogs.h"
49 #include "file_sndfile.h"
50 #include "interface.h"
51 #include "question_dialogs.h"
52 #include "sw_chooser.h"
53 #include "view.h"
54
55 extern GtkStyle * style_wb;
56
57 #if defined (SNDFILE_1)
58
59 #include "../pixmaps/libsndfile.xpm"
60
61 typedef struct {
62   int subformat;
63   gboolean cap_mono;
64   gboolean cap_stereo;
65 } sndfile_subformat_caps;
66
67 typedef struct {
68   gboolean saving; /* loading or saving ? */
69   sw_sample * sample;
70   gchar * pathname;
71   SF_INFO * sfinfo;
72   GtkWidget * ok_button;
73 } sndfile_save_options;
74
75 static void
76 sweep_sndfile_perror (SNDFILE * sndfile, gchar * pathname)
77 {
78   char buf[128];
79
80   sf_error_str (sndfile, buf, sizeof (buf));
81
82   sweep_perror (errno, "libsndfile: %s\n\n%s", buf,
83                 (pathname == NULL) ? "" : pathname);
84 }
85
86 static void
87 sndfile_save_options_dialog_ok_cb (GtkWidget * widget, gpointer data)
88 {
89   sndfile_save_options * so = (sndfile_save_options *)data;
90   sw_sample * sample = so->sample;
91   GtkWidget * dialog;
92
93   dialog = gtk_widget_get_toplevel (widget);
94   gtk_widget_destroy (dialog);
95
96   if (sample->file_info) {
97     g_free (sample->file_info);
98   }
99
100   sample->file_info = so->sfinfo;
101
102   sndfile_sample_save (sample, so->pathname);
103
104   g_free (so);
105 }
106
107 static void
108 sndfile_save_options_dialog_cancel_cb (GtkWidget * widget, gpointer data)
109 {
110   sndfile_save_options * so = (sndfile_save_options *)data;
111   GtkWidget * dialog;
112
113   dialog = gtk_widget_get_toplevel (widget);
114   gtk_widget_destroy (dialog);
115
116   g_free (so);
117
118   /* if the sample bank is empty, quit the program */
119   sample_bank_remove (NULL);
120 }
121
122 static void
123 update_ok_button (sndfile_save_options * so)
124 {
125   g_return_if_fail (so != NULL);
126
127   gtk_widget_set_sensitive (so->ok_button,
128                             so->sfinfo->samplerate > 0 &&
129                             sf_format_check (so->sfinfo));
130 }
131
132 static void
133 update_save_options_caps (sndfile_save_options * so)
134 {
135   update_ok_button (so);
136 }
137
138 static void
139 update_save_options_values (sndfile_save_options * so)
140 {
141   sw_sample * sample;
142   sw_format * format;
143   SF_INFO * sfinfo;
144
145   sample = so->sample;
146   format = sample->sounddata->format;
147
148   sfinfo = so->sfinfo;
149
150   update_ok_button (so);
151 }
152
153 static void
154 set_subformat_cb (GtkWidget * widget, gpointer data)
155 {
156   sndfile_save_options * so = (sndfile_save_options *)data;
157   SF_INFO * sfinfo = so->sfinfo;
158   int subformat;
159
160   sfinfo->format &= SF_FORMAT_TYPEMASK; /* clear submask */
161
162   subformat =
163     GPOINTER_TO_INT(g_object_get_data (G_OBJECT(widget), "default"));
164   subformat &= SF_FORMAT_SUBMASK; /* get new subformat */
165
166   sfinfo->format |= subformat;
167
168   update_save_options_caps (so);
169 }
170
171 static void
172 set_rate_cb (GtkWidget * widget, gint samplerate, gpointer data)
173 {
174   sndfile_save_options * so = (sndfile_save_options *)data;
175   SF_INFO * sfinfo = so->sfinfo;
176
177   sfinfo->samplerate = samplerate;
178
179   update_ok_button (so);
180 }
181
182 static void
183 set_channels_cb (GtkWidget * widget, gint channels, gpointer data)
184 {
185   sndfile_save_options * so = (sndfile_save_options *)data;
186   SF_INFO * sfinfo = so->sfinfo;
187
188   sfinfo->channels = channels;
189
190   update_ok_button (so);
191 }
192
193 static GtkWidget *
194 create_sndfile_encoding_options_dialog (sndfile_save_options * so)
195 {
196   GtkWidget * dialog;
197   GtkWidget * ebox;
198   GtkWidget * pixmap;
199   GtkWidget * main_vbox;
200   GtkWidget * notebook;
201   GtkWidget * vbox;
202   GtkWidget * table;
203   GtkWidget * hbox;
204   GtkWidget * label;
205   GtkWidget * option_menu;
206   GtkWidget * menu;
207   GtkWidget * menuitem;
208   GtkWidget * entry;
209   GtkWidget * ok_button, * button;
210
211 /*GtkStyle * style;*/
212
213   GtkTooltips * tooltips;
214
215   sw_sample * sample = so->sample;
216   SF_INFO * sfinfo = so->sfinfo;
217   int subformat;
218
219   SF_FORMAT_INFO  info ;
220   int   k, count ;
221
222   SF_INFO tmp_sfinfo;
223        
224   dialog = gtk_dialog_new ();
225   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
226  
227   attach_window_close_accel(GTK_WINDOW(dialog));
228
229   /* Set up the action area first so the sensitivity of the ok button
230    *  can be updated by formats below. */
231
232   /* OK */
233
234   ok_button = gtk_button_new_with_label (_("OK"));
235   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (ok_button), GTK_CAN_DEFAULT);
236   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), ok_button,
237                       TRUE, TRUE, 0);
238   gtk_widget_show (ok_button);
239
240   so->ok_button = ok_button;
241
242   /* Cancel */
243
244   button = gtk_button_new_with_label (_("Cancel"));
245   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (button), GTK_CAN_DEFAULT);
246   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), button,
247                       TRUE, TRUE, 0);
248   gtk_widget_show (button);
249   g_signal_connect (G_OBJECT(button), "clicked",
250                       G_CALLBACK (sndfile_save_options_dialog_cancel_cb),
251                       so);
252
253
254
255   main_vbox = GTK_DIALOG(dialog)->vbox;
256
257   ebox = gtk_event_box_new ();
258   gtk_box_pack_start (GTK_BOX(main_vbox), ebox, FALSE, FALSE, 0);
259   gtk_widget_set_style (ebox, style_wb);
260   gtk_widget_show (ebox);
261
262   vbox = gtk_vbox_new (FALSE, 0);
263   gtk_container_add (GTK_CONTAINER(ebox), vbox);
264   gtk_widget_show (vbox);
265
266   hbox = gtk_hbox_new (FALSE, 0);
267   gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
268   gtk_widget_show (hbox);
269
270   pixmap = create_widget_from_xpm (dialog, libsndfile_xpm);
271   gtk_box_pack_start (GTK_BOX (hbox), pixmap, FALSE, FALSE, 0);
272   gtk_widget_show (pixmap);
273
274   tooltips = gtk_tooltips_new ();
275   gtk_tooltips_set_tip (tooltips, ebox,
276                         _("Powered by libsndfile"),
277                         NULL);
278
279   /* Filename */
280
281 /* pangoise?
282
283   style = gtk_style_copy (style_wb);
284   gdk_font_unref (style->font);
285   style->font =
286   gdk_font_load("-*-helvetica-medium-r-normal-*-*-180-*-*-*-*-*-*");
287   gtk_widget_push_style (style);
288 */
289   label = gtk_label_new (g_basename (so->pathname));
290   gtk_box_pack_start (GTK_BOX(vbox), label,
291                       FALSE, FALSE, 8);
292   gtk_widget_show (label);
293  
294 /*gtk_widget_pop_style ();*/
295
296   notebook = gtk_notebook_new ();
297   gtk_box_pack_start (GTK_BOX(main_vbox), notebook, TRUE, TRUE, 4);
298   gtk_widget_show (notebook);
299
300   /* Options */
301
302   /* XXX: prepend major format name */
303   label = gtk_label_new (_("Encoding"));
304
305   vbox = gtk_vbox_new (FALSE, 0);
306   gtk_notebook_append_page (GTK_NOTEBOOK(notebook), vbox, label);
307   gtk_container_set_border_width (GTK_CONTAINER(vbox), 4);
308   gtk_widget_show (vbox);
309
310   /* Encoding */
311
312   table = gtk_table_new (4, 2, FALSE);
313   gtk_table_set_row_spacings (GTK_TABLE(table), 8);
314   gtk_table_set_col_spacings (GTK_TABLE(table), 8);
315   gtk_box_pack_start (GTK_BOX(vbox), table, FALSE, FALSE, 0);
316   gtk_container_set_border_width (GTK_CONTAINER(table), 8);
317   gtk_widget_show (table);
318
319   hbox = gtk_hbox_new (FALSE, 0);
320   gtk_table_attach (GTK_TABLE(table), hbox, 0, 1, 0, 1,
321                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
322   gtk_widget_show (hbox);
323  
324   label = gtk_label_new (_("Encoding:"));
325   gtk_box_pack_end (GTK_BOX(hbox), label, FALSE, FALSE, 0);
326   gtk_widget_show (label);
327
328   option_menu = gtk_option_menu_new ();
329   gtk_table_attach (GTK_TABLE(table), option_menu, 1, 2, 0, 1,
330                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
331   gtk_widget_show (option_menu);
332
333   menu = gtk_menu_new ();
334
335   /*------------------------------------------------------*/
336   subformat = sfinfo->format & SF_FORMAT_SUBMASK;
337
338   sf_command (NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int)) ;
339
340   for (k = 0 ; k < count ; k++) {
341     info.format = k ;
342     sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &info, sizeof (info)) ;
343
344     memset (&tmp_sfinfo, 0, sizeof (SF_INFO));
345     tmp_sfinfo.channels = 1;
346     tmp_sfinfo.format = (sfinfo->format & SF_FORMAT_TYPEMASK) | info.format;
347
348     if (sf_format_check (&tmp_sfinfo)) {
349       if (subformat == 0) {
350         sfinfo->format |= info.format;
351         subformat = info.format;
352       }
353
354       menuitem = gtk_menu_item_new_with_label (info.name);
355       g_object_set_data (G_OBJECT(menuitem), "default",
356                                 GINT_TO_POINTER(info.format));
357       g_signal_connect (G_OBJECT(menuitem), "activate",
358                           G_CALLBACK(set_subformat_cb), so);
359       gtk_menu_append (GTK_MENU(menu), menuitem);
360       gtk_widget_show (menuitem);
361       if (info.format == subformat) {
362         gtk_menu_item_select (GTK_MENU_ITEM(menuitem));
363       }
364     }
365   }
366
367  
368
369   /*------------------------------------------------------*/
370  
371   gtk_option_menu_set_menu (GTK_OPTION_MENU(option_menu), menu);
372   gtk_widget_show (menu);
373
374   /* Rate */
375
376   if (!so->saving) {
377     entry = samplerate_chooser_new (NULL);
378     gtk_table_attach (GTK_TABLE(table), entry, 0, 2, 1, 2,
379                       GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
380     gtk_widget_show (entry);
381
382     g_signal_connect (G_OBJECT(entry), "number-changed",
383                         G_CALLBACK(set_rate_cb), so);
384
385     if (sample == NULL)
386       so->sfinfo->samplerate = samplerate_chooser_get_rate (entry);
387     else
388       samplerate_chooser_set_rate (entry, sample->sounddata->format->rate);
389
390   } else {
391     hbox = gtk_hbox_new (FALSE, 0);
392     gtk_table_attach (GTK_TABLE(table), hbox, 0, 1, 1, 2,
393                       GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
394     gtk_widget_show (hbox);
395    
396     label = gtk_label_new (_("Sampling rate:"));
397     gtk_box_pack_end (GTK_BOX(hbox), label, FALSE, FALSE, 0);
398     gtk_widget_show (label);
399    
400     hbox = gtk_hbox_new (FALSE, 0);
401     gtk_table_attach (GTK_TABLE(table), hbox, 1, 2, 1, 2,
402                       GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
403     gtk_widget_show (hbox);
404
405     label = gtk_label_new (g_strdup_printf ("%d Hz",
406                                             sample->sounddata->format->rate));
407     gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
408     gtk_widget_show (label);
409   }
410
411   /* Channels */
412
413   entry = channelcount_chooser_new (NULL);
414   gtk_table_attach (GTK_TABLE(table), entry, 0, 2, 2, 3,
415                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
416   gtk_widget_show (entry);
417  
418   g_signal_connect (G_OBJECT(entry), "number-changed",
419                       G_CALLBACK(set_channels_cb), so);
420
421   if (sample == NULL)
422     so->sfinfo->channels = channelcount_chooser_get_count (entry);
423   else
424     channelcount_chooser_set_count (entry,
425                                     sample->sounddata->format->channels);
426
427   /* About */
428
429   label = gtk_label_new (_("About"));
430
431   ebox = gtk_event_box_new ();
432   gtk_notebook_append_page (GTK_NOTEBOOK(notebook), ebox, label);
433   gtk_widget_set_style (ebox, style_wb);
434   gtk_widget_show (ebox);
435
436   gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK(notebook), ebox,
437                                       TRUE, TRUE, GTK_PACK_END);
438
439   vbox = gtk_vbox_new (FALSE, 16);
440   gtk_container_add (GTK_CONTAINER(ebox), vbox);
441   gtk_container_set_border_width (GTK_CONTAINER(vbox), 8);
442   gtk_widget_show (vbox);
443
444   label =
445     gtk_label_new (_("Libsndfile is a C library by Erik de Castro Lopo\n"
446                      "for reading and writing files containing sampled sound."));
447
448   gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
449   gtk_widget_set_style (label, style_wb);
450   gtk_widget_show (label);
451
452   button = gtk_hseparator_new ();
453   gtk_box_pack_start (GTK_BOX(vbox), button, FALSE, FALSE, 8);
454   gtk_widget_show (button);
455
456   label = gtk_label_new (_("This user interface by Erik de Castro Lopo\n"
457                            " and Conrad Parker,\n"
458                            "Copyright (C) 2002 Erik de Castro Lopo\n"
459                            "Copyright (C) 2002 CSIRO Australia.\n\n"));
460   gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
461   gtk_widget_set_style (label, style_wb);
462   gtk_widget_show (label);
463
464
465   gtk_widget_grab_default (ok_button);
466
467   update_save_options_caps (so);
468   update_save_options_values (so);
469
470   return (dialog);
471 }
472
473 int
474 sndfile_save_options_dialog (sw_sample * sample, gchar * pathname)
475 {
476   GtkWidget * dialog;
477   sndfile_save_options * so;
478   SF_INFO * sfinfo;
479   sw_format * format;
480
481   so = g_malloc0 (sizeof(*so));
482   so->saving = TRUE;
483
484   so->sample = sample;
485
486   sfinfo = g_malloc0 (sizeof(SF_INFO));
487
488   format = sample->sounddata->format;
489   sfinfo->frames = (sf_count_t)sample->sounddata->nr_frames;
490   sfinfo->samplerate = (int)format->rate;
491   sfinfo->channels = (int)format->channels;
492
493   sfinfo->format = sample->file_format;
494
495   so->pathname = g_strdup (pathname);
496   so->sfinfo = sfinfo;
497
498   dialog = create_sndfile_encoding_options_dialog (so);
499   gtk_window_set_title (GTK_WINDOW(dialog), _("Sweep: Save PCM options"));
500
501   g_signal_connect (G_OBJECT(so->ok_button), "clicked",
502                       G_CALLBACK (sndfile_save_options_dialog_ok_cb),
503                       so);
504
505   gtk_widget_show (dialog);
506
507   return 0;
508 }
509
510 typedef struct _sf_data sf_data;
511
512 struct _sf_data {
513   SNDFILE * sndfile;
514   SF_INFO * sfinfo;
515 };
516
517 static sw_sample *
518 _sndfile_sample_load (sw_sample * sample, gchar * pathname, SF_INFO * sfinfo,
519                       gboolean try_raw);
520
521 static void
522 sndfile_load_options_dialog_ok_cb (GtkWidget * widget, gpointer data)
523 {
524   sndfile_save_options * so = (sndfile_save_options *)data;
525   sw_sample * sample = so->sample;
526   gchar * pathname = so->pathname;
527   SF_INFO * sfinfo = so->sfinfo;
528   GtkWidget * dialog;
529
530   dialog = gtk_widget_get_toplevel (widget);
531   gtk_widget_destroy (dialog);
532
533   _sndfile_sample_load (sample, pathname, sfinfo, TRUE);
534
535   g_free (so->pathname);
536   g_free (so);
537 }
538
539
540 static sw_sample *
541 sample_load_sf_data (sw_op_instance * inst)
542 {
543   sw_sample * sample = inst->sample;
544   sf_data * sf = (sf_data *)inst->do_data;
545   SNDFILE * sndfile = sf->sndfile;
546   SF_INFO * sfinfo = sf->sfinfo;
547   sw_audio_t * d;
548   sw_framecount_t remaining, n, run_total;
549   sw_framecount_t cframes;
550   gint percent;
551
552   struct stat statbuf;
553
554   gboolean active = TRUE;
555
556   sf_command (sndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE) ;
557
558   remaining = sfinfo->frames;
559   run_total = 0;
560
561   d = sample->sounddata->data;
562
563   cframes = sfinfo->frames / 100;
564   if (cframes == 0) cframes = 1;
565
566   while (active && remaining > 0) {
567     g_mutex_lock (sample->ops_mutex);
568
569     if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
570       active = FALSE;
571     } else {
572       n = MIN (remaining, 1024);
573       n = sf_readf_float (sndfile, d, n);
574
575       if (n == 0) {
576         sweep_sndfile_perror (sndfile, sample->pathname);
577         active = FALSE;
578       }
579
580       remaining -= n;
581
582       d += (n * sfinfo->channels);
583
584       run_total += n;
585       percent = run_total / cframes;
586       sample_set_progress_percent (sample, percent);
587     }
588
589     g_mutex_unlock (sample->ops_mutex);
590   }
591
592   sf_close (sndfile) ;
593
594   if (remaining <= 0) {
595     stat (sample->pathname, &statbuf);
596     sample->last_mtime = statbuf.st_mtime;
597     sample->edit_ignore_mtime = FALSE;
598     sample->modified = FALSE;
599   }
600
601   sample_set_edit_state (sample, SWEEP_EDIT_STATE_DONE);
602
603   return sample;
604 }
605
606 static sw_operation sndfile_load_op = {
607   SWEEP_EDIT_MODE_FILTER,
608   (SweepCallback)sample_load_sf_data,
609   (SweepFunction)NULL,
610   (SweepCallback)NULL, /* undo */
611   (SweepFunction)NULL,
612   (SweepCallback)NULL, /* redo */
613   (SweepFunction)NULL
614 };
615
616 static sw_sample *
617 _sndfile_sample_load (sw_sample * sample, gchar * pathname, SF_INFO * sfinfo,
618                       gboolean try_raw)
619 {
620   SNDFILE * sndfile;
621   char buf[128];
622   gchar * message;
623
624   gboolean isnew = (sample == NULL);
625
626   sndfile_save_options * so;
627   GtkWidget * dialog;
628
629   sw_view * v;
630
631   sf_data * sf;
632
633 #define RAW_ERR_STR_1 \
634 "Bad format specified for file open."
635
636 #define RAW_ERR_STR_2 \
637 "File opened for read. Format not recognised."
638
639   if (sfinfo == NULL)
640     sfinfo = g_malloc0 (sizeof (SF_INFO));
641
642   if (!(sndfile = sf_open (pathname, SFM_READ, sfinfo) )) {
643     /* If we're not trying raw files anyway, just return NULL */
644     if (!try_raw) {
645       g_free (sfinfo);
646       return NULL;
647     }
648
649     sf_error_str (NULL, buf, sizeof (buf));
650     if (!strncmp (buf, RAW_ERR_STR_1, sizeof (buf)) ||
651         !strncmp (buf, RAW_ERR_STR_2, sizeof (buf))) {
652
653       so = g_malloc0 (sizeof(*so));
654       so->saving = FALSE;
655       so->sample = sample;
656       so->pathname = g_strdup (pathname);
657       so->sfinfo = sfinfo;
658
659       sfinfo->format = (SF_FORMAT_RAW | SF_FORMAT_PCM_S8);
660       sfinfo->samplerate = 44100;
661       /*-sfinfo->pcmbitwidth = 8;-*/
662       sfinfo->channels = 2;
663
664       dialog = create_sndfile_encoding_options_dialog (so);
665       gtk_window_set_title (GTK_WINDOW(dialog),
666                             _("Sweep: Load Raw PCM options"));
667
668       g_signal_connect (G_OBJECT(so->ok_button), "clicked",
669                           G_CALLBACK (sndfile_load_options_dialog_ok_cb),
670                           so);
671
672       gtk_widget_show (dialog);
673
674     } else {
675       if (errno == 0) {
676         message = g_strdup_printf ("%s:\n%s", pathname, buf);
677         info_dialog_new (buf, NULL, message);
678         g_free (message);
679       } else {
680         /* We've already got the error string so no need to call
681          * sweep_sndfile_perror() here */
682         sweep_perror (errno, "libsndfile: %s\n\n%s", buf, pathname);
683       }
684
685       g_free (sfinfo);
686     }
687
688     return NULL;
689   }
690
691   if (sample == NULL) {
692     sample = sample_new_empty(pathname, sfinfo->channels, sfinfo->samplerate,
693                               (sw_framecount_t)sfinfo->frames);
694   } else {
695     sounddata_destroy (sample->sounddata);
696     sample->sounddata =
697       sounddata_new_empty (sfinfo->channels, sfinfo->samplerate,
698                            (sw_framecount_t)sfinfo->frames);
699   }
700
701   if(!sample) {
702     g_free (sfinfo);
703     return NULL;
704   }
705
706   sample->file_method = SWEEP_FILE_METHOD_LIBSNDFILE;
707   sample->file_info = sfinfo;
708
709   sample_bank_add(sample);
710
711   if (isnew) {
712     v = view_new_all (sample, 1.0);
713     sample_add_view (sample, v);
714   } else {
715     trim_registered_ops (sample, 0);
716   }
717
718   g_snprintf (buf, sizeof (buf), _("Loading %s"), g_basename (sample->pathname));
719
720   sf = g_malloc0 (sizeof(sf_data));
721
722   sf->sndfile = sndfile;
723   sf->sfinfo = sfinfo;
724
725   schedule_operation (sample, buf, &sndfile_load_op, sf);
726
727   return sample;
728 }
729
730 sw_sample *
731 sndfile_sample_reload (sw_sample * sample, gboolean try_raw)
732 {
733   if (sample == NULL) return NULL;
734
735   return _sndfile_sample_load (sample, sample->pathname, NULL, try_raw);
736 }
737
738 sw_sample *
739 sndfile_sample_load (gchar * pathname, gboolean try_raw)
740 {
741   if (pathname == NULL) return NULL;
742
743   return _sndfile_sample_load (NULL, pathname, NULL, try_raw);
744 }
745
746 static int
747 sndfile_sample_save_thread (sw_op_instance * inst)
748 {
749   sw_sample * sample = inst->sample;
750   gchar * pathname = (gchar *)inst->do_data;
751
752   SNDFILE *sndfile;
753   SF_INFO * sfinfo;
754   sw_format * format;
755   sw_audio_t * fbuf, * d;
756   sw_framecount_t nwritten = 0, len, n;
757   sw_framecount_t cframes;
758   int i, j;
759   gint percent;
760
761   gboolean active = TRUE;
762
763   struct stat statbuf;
764
765   if (sample == NULL) return -1;
766   if (pathname == NULL) return -1;
767
768   format = sample->sounddata->format;
769
770   sfinfo = (SF_INFO *)sample->file_info;
771
772   if (sfinfo == NULL) {
773     sfinfo = g_malloc0 (sizeof(*sfinfo));
774     sample->file_info = sfinfo;
775   }
776
777   sfinfo->samplerate  = (int)format->rate;
778   sfinfo->frames     = (sf_count_t)sample->sounddata->nr_frames;
779
780   if (!(sndfile = sf_open (pathname, SFM_WRITE, sfinfo))) {
781     sweep_sndfile_perror (NULL, pathname);
782     return -1;
783   }
784
785   /* Reset sample count which gets destroyed in open for write call. */
786   sfinfo->frames     = (sf_count_t)sample->sounddata->nr_frames;
787
788   sf_command (sndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE) ;
789   sf_command (sndfile, SFC_SET_ADD_DITHER_ON_WRITE, NULL, SF_TRUE);
790
791   cframes = sfinfo->frames / 100;
792   if (cframes == 0) cframes = 1;
793
794   if ((int)format->channels == sfinfo->channels) {
795     fbuf = sample->sounddata->data;
796     while (active && nwritten < sfinfo->frames) {
797       g_mutex_lock (sample->ops_mutex);
798
799       if (sample->edit_mode == SWEEP_EDIT_MODE_META) {
800         len = MIN (sfinfo->frames - nwritten, 1024);
801         n = sf_writef_float (sndfile, fbuf, len);
802
803         if (n == 0) {
804           sweep_sndfile_perror (sndfile, pathname);
805           active = FALSE;
806         }
807
808         fbuf += n * sfinfo->channels;
809         nwritten += n;
810         percent = nwritten / cframes;
811         sample_set_progress_percent (sample, percent);
812       } else {
813         active = FALSE;
814       }
815
816       g_mutex_unlock (sample->ops_mutex);
817     }
818   } else if (format->channels == 1 && sfinfo->channels == 2) {
819     /* Duplicate mono to stereo */
820     fbuf = (sw_audio_t *)alloca(1024 * sizeof(sw_audio_t));
821     d = sample->sounddata->data;
822     while (active && nwritten < sfinfo->frames) {
823       g_mutex_lock (sample->ops_mutex);
824
825       if (sample->edit_mode == SWEEP_EDIT_MODE_META) {
826         len = MIN (sfinfo->frames - nwritten, 512);
827         for (i = 0; i < len; i++) {
828           fbuf[i*2] = fbuf[i*2+1] = *d++;
829         }
830         n = sf_writef_float (sndfile, fbuf, len);
831
832         if (n == 0) {
833           sweep_sndfile_perror (sndfile, pathname);
834           active = FALSE;
835         }
836
837         nwritten += n;
838         percent = nwritten / cframes;
839         sample_set_progress_percent (sample, percent);
840       } else {
841         active = FALSE;
842       }
843
844       g_mutex_unlock (sample->ops_mutex);
845     }
846   } else if (format->channels == 2 && sfinfo->channels == 1) {
847     /* Mix down stereo to mono */
848     fbuf = (sw_audio_t *)alloca(1024 * sizeof(sw_audio_t));
849     d = sample->sounddata->data;
850     while (active && nwritten < sfinfo->frames) {
851       g_mutex_lock (sample->ops_mutex);
852
853       if (sample->edit_mode == SWEEP_EDIT_MODE_META) {
854         len = MIN (sfinfo->frames - nwritten, 1024);
855         for (i = 0; i < len; i++) {
856           fbuf[i] = *d++;
857           fbuf[i] += *d++;
858           fbuf[i] /= 2.0;
859         }
860         n = sf_writef_float (sndfile, fbuf, len);
861
862         if (n == 0) {
863           sweep_sndfile_perror (sndfile, pathname);
864           active = FALSE;
865         }
866
867         nwritten += n;
868         percent = nwritten / cframes;
869         sample_set_progress_percent (sample, percent);
870       } else {
871         active = FALSE;
872       }
873
874       g_mutex_unlock (sample->ops_mutex);
875     }
876   } else {
877     gint min_channels = MIN (format->channels, sfinfo->channels);
878     size_t buf_size = 1024 * sizeof (sw_audio_t) * sfinfo->channels;
879
880     /* Copy corresponding channels as much as possible */
881     fbuf = (sw_audio_t *)alloca(buf_size);
882     memset (fbuf, 0, buf_size);
883     d = sample->sounddata->data;
884     while (active && nwritten < sfinfo->frames) {
885       g_mutex_lock (sample->ops_mutex);
886
887       if (sample->edit_mode == SWEEP_EDIT_MODE_META) {
888         len = MIN (sfinfo->frames - nwritten, 1024);
889         for (i = 0; i < len; i++) {
890           for (j = 0; j < min_channels; j++) {
891             fbuf[i*sfinfo->channels + j] = d[j];
892           }
893           d += format->channels;
894         }
895
896         n = sf_writef_float (sndfile, fbuf, len);
897
898         if (n == 0) {
899           sweep_sndfile_perror (sndfile, pathname);
900           active = FALSE;
901         }
902
903         nwritten += n;
904         percent = nwritten / cframes;
905         sample_set_progress_percent (sample, percent);
906       } else {
907         active = FALSE;
908       }
909
910       g_mutex_unlock (sample->ops_mutex);
911     }
912   }
913
914   sf_close (sndfile) ;
915
916   if (nwritten >= sfinfo->frames) {
917     stat (pathname, &statbuf);
918     sample->last_mtime = statbuf.st_mtime;
919     sample->edit_ignore_mtime = FALSE;
920     sample->modified = FALSE;
921
922     sample_store_and_free_pathname (sample, pathname);
923   }
924
925   sample_set_edit_state (sample, SWEEP_EDIT_STATE_DONE);
926
927   return 0;
928 }
929
930 static sw_operation sndfile_save_op = {
931   SWEEP_EDIT_MODE_META,
932   (SweepCallback)sndfile_sample_save_thread,
933   (SweepFunction)NULL,
934   (SweepCallback)NULL, /* undo */
935   (SweepFunction)NULL,
936   (SweepCallback)NULL, /* redo */
937   (SweepFunction)NULL
938 };
939
940 int
941 sndfile_sample_save (sw_sample * sample, gchar * pathname)
942 {
943   char buf[128];
944
945   g_snprintf (buf, sizeof (buf), _("Saving %s"), g_basename (pathname));
946
947   schedule_operation (sample, buf, &sndfile_save_op, g_strdup (pathname));
948
949   return 0;
950 }
951
952 #endif
Note: See TracBrowser for help on using the browser.