root/sweep/trunk/src/file_vorbis.c

Revision 704, 45.4 kB (checked in by erikd, 2 years ago)

src/file_vorbis.c : Define OV_EXCLUDE_STATIC_CALLBACKS to prevent compiler warnings from <vorbis/vorbisfile.h> header.

  • 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  * Copyright (C) 2002 CSIRO Australia
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 /*
23  * This file adapted from "decoder_example.c" and "encoder_example.c" in
24  * the OggVorbis software codec source code, Copyright (C) 1994-2002 by
25  * the XIPHOPHORUS Company.
26  *
27  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS
28  * GOVERNED BY the following BSD-style license.
29  *
30  * Copyright (c) 2002, Xiph.org Foundation
31  *
32  * Redistribution and use in source and binary forms, with or without
33  * modification, are permitted provided that the following conditions
34  * are met:
35  *
36  * - Redistributions of source code must retain the above copyright
37  * notice, this list of conditions and the following disclaimer.
38  *
39  * - Redistributions in binary form must reproduce the above copyright
40  * notice, this list of conditions and the following disclaimer in the
41  * documentation and/or other materials provided with the distribution.
42  *
43  * - Neither the name of the Xiph.org Foundation nor the names of its
44  * contributors may be used to endorse or promote products derived from
45  * this software without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
48  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
49  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
50  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
51  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
52  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
53  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
54  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
55  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
56  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
57  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58  *
59  */
60
61 #ifdef HAVE_CONFIG_H
62 #  include <config.h>
63 #endif
64
65 #ifdef HAVE_OGGVORBIS
66
67 #include <stdlib.h>
68 #include <stdio.h>
69 #include <string.h>
70 #include <sys/stat.h>
71 #include <math.h>
72 #include <pthread.h>
73 #include <errno.h>
74 #include <ctype.h>
75
76 #define OV_EXCLUDE_STATIC_CALLBACKS
77
78 #include <vorbis/codec.h>
79 #include <vorbis/vorbisfile.h>
80 #include <vorbis/vorbisenc.h>
81
82 #include <glib.h>
83 #include <gdk/gdkkeysyms.h>
84 #include <gtk/gtk.h>
85
86 #include <sweep/sweep_i18n.h>
87 #include <sweep/sweep_types.h>
88 #include <sweep/sweep_typeconvert.h>
89 #include <sweep/sweep_sample.h>
90 #include <sweep/sweep_undo.h>
91 #include <sweep/sweep_sounddata.h>
92
93 #include "sample.h"
94 #include "interface.h"
95 #include "file_dialogs.h"
96 #include "file_sndfile.h"
97 #include "question_dialogs.h"
98 #include "preferences.h"
99 #include "print.h"
100 #include "view.h"
101
102 #include "../pixmaps/white-ogg.xpm"
103 #include "../pixmaps/vorbisword2.xpm"
104 #include "../pixmaps/xifish.xpm"
105
106 #define QUALITY_KEY "OggVorbis_Quality"
107 #define ABR_KEY "OggVorbis_ABR"
108 #define NOMINAL_KEY "OggVorbis_NominalBR"
109 #define MINIMUM_KEY "OggVorbis_MinBR"
110 #define MAXIMUM_KEY "OggVorbis_MaxBR"
111 #define SERIALNO_KEY "OggVorbis_Serialno"
112
113 #define DEFAULT_NOMINAL 128L
114 #define DEFAULT_QUALITY 3.0
115
116 extern GtkStyle * style_bw;
117
118 #ifdef DEVEL_CODE
119 typedef struct _sw_metadata sw_metadata;
120
121 struct _sw_metadata {
122   char * name;
123   char * content;
124 };
125
126 static sw_metadata *
127 vorbis_metadata_from_str (char * str)
128 {
129   sw_metadata * meta = NULL;
130   gint i;
131
132   for (i = 0; str[i]; i++) {
133     if (i == 0) {
134       str[i] = toupper(str[i]);
135     } else {
136       str[i] = tolower(str[i]);
137     }
138
139     if (str[i] == '=') {
140       str[i] = '\0';
141       meta = g_malloc (sizeof (sw_metadata));
142       meta->name = g_strdup (str);
143       meta->content = g_strdup (&str[i+1]);
144       break;
145     }
146   }
147
148   return meta;
149 }
150 #endif /* DEVEL_CODE */
151
152 static sw_sample *
153 sample_load_vorbis_data (sw_op_instance * inst)
154 {
155   sw_sample * sample = inst->sample;
156   OggVorbis_File * vf = (OggVorbis_File *)sample->file_info;
157   int channels;
158   float ** pcm;
159   int i, j;
160   sw_audio_t * d;
161   sw_framecount_t remaining, n, run_total;
162   sw_framecount_t cframes;
163   gint percent;
164
165   int bitstream;
166
167   struct stat statbuf;
168
169   gboolean active = TRUE;
170
171   channels = sample->sounddata->format->channels;
172
173   remaining = sample->sounddata->nr_frames;
174   run_total = 0;
175
176   d = sample->sounddata->data;
177
178   cframes = remaining / 100;
179   if (cframes == 0) cframes = 1;
180
181   while (active && remaining > 0) {
182     g_mutex_lock (sample->ops_mutex);
183
184     if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
185       active = FALSE;
186     } else {
187       n = MIN (remaining, 1024);
188
189 #ifdef OV_READ_FLOAT_THREE_ARGS
190       n = ov_read_float (vf, &pcm, &bitstream);
191 #else
192       n = ov_read_float (vf, &pcm, n, &bitstream);
193 #endif
194
195       if (n == 0) {
196         /* EOF */
197         remaining = 0;
198       } else if (n < 0) {
199         /* XXX: corrupt data; ignore? */
200       } else {
201
202         for (i = 0; i < channels; i++) {
203           for (j = 0; j < n; j++) {
204             d[j*channels + i] = pcm[i][j];
205           }
206         }
207        
208         d += (n * channels);
209
210         remaining -= n;
211        
212         run_total += n;
213         percent = run_total / cframes;
214         sample_set_progress_percent (sample, percent);
215       }
216     }
217
218     g_mutex_unlock (sample->ops_mutex);
219   }
220
221   ov_clear (vf);
222
223   stat (sample->pathname, &statbuf);
224   sample->last_mtime = statbuf.st_mtime;
225   sample->edit_ignore_mtime = FALSE;
226   sample->modified = FALSE;
227
228   sample_set_edit_state (sample, SWEEP_EDIT_STATE_DONE);
229
230   return sample;
231 }
232
233 static sw_operation vorbis_load_op = {
234   SWEEP_EDIT_MODE_FILTER,
235   (SweepCallback)sample_load_vorbis_data,
236   (SweepFunction)NULL,
237   (SweepCallback)NULL, /* undo */
238   (SweepFunction)NULL,
239   (SweepCallback)NULL, /* redo */
240   (SweepFunction)NULL
241 };
242
243 static sw_sample *
244 sample_load_vorbis_info (sw_sample * sample, char * pathname)
245 {
246   FILE * f;
247   OggVorbis_File * vf;
248   vorbis_info * vi;
249   int ret;
250
251   char buf[128];
252
253   gboolean isnew = (sample == NULL);
254
255   sw_view * v;
256
257   f = fopen (pathname, "r");
258
259   vf = g_malloc (sizeof (OggVorbis_File));
260
261   if ((ret = ov_open (f, vf, NULL, 0)) < 0) {
262     switch (ret) {
263     case OV_EREAD:
264       printf ("vorbis: read from media returned an error\n");
265       break;
266     case OV_ENOTVORBIS:
267       /* No need to report this one -- this was not a vorbis file */
268 #ifdef DEBUG
269       printf ("vorbis: Bitstream is not Vorbis data\n");
270 #endif
271       break;
272     case OV_EVERSION:
273       printf ("vorbis: Vorbis version mismatch\n");
274       break;
275     case OV_EBADHEADER:
276       printf ("vorbis: Invalid Vorbis bitstream header\n");
277       break;
278     case OV_EFAULT:
279       printf ("vorbis: Internal logic fault\n");
280       break;
281     default:
282       break;
283     }
284
285     g_free (vf);
286
287     return NULL;
288   }
289
290   /* Get the vorbis info (channels, rate) */
291   vi = ov_info (vf, -1);
292
293   if (sample == NULL) {
294     sample = sample_new_empty(pathname, vi->channels, vi->rate,
295                               (sw_framecount_t) ov_pcm_total (vf, -1));
296   } else {
297     sounddata_destroy (sample->sounddata);
298     sample->sounddata =
299       sounddata_new_empty (vi->channels, vi->rate,
300                            (sw_framecount_t) ov_pcm_total (vf, -1));
301   }
302
303   if(!sample) {
304     g_free (vf);
305     return NULL;
306   }
307
308   sample->file_method = SWEEP_FILE_METHOD_OGGVORBIS;
309   sample->file_info = vf;
310
311   sample_bank_add(sample);
312
313   if (isnew) {
314     v = view_new_all (sample, 1.0);
315     sample_add_view (sample, v);
316   } else {
317     trim_registered_ops (sample, 0);
318   }
319
320   g_snprintf (buf, sizeof (buf), _("Loading %s"), g_basename (sample->pathname));
321
322 #ifdef DEVEL_CODE
323   /* Throw the comments plus a few lines about the bitstream we're
324      decoding */
325   {
326     GList * metadata_list = NULL;
327     sw_metadata * metadata = NULL;
328
329     char buf[1024];
330     int n = 0;
331
332     char **ptr = ov_comment(vf, -1)->user_comments;
333
334     while(*ptr) {
335       metadata = vorbis_metadata_from_str (*ptr);
336
337       if (metadata != NULL) {
338         /* Store the metadata for later use, except the encoder comment */
339         if (g_strcasecmp (metadata->content, "encoder"))
340           metadata_list = g_list_append (metadata_list, metadata);
341
342         n += snprintf (buf+n, sizeof (buf)-n, "%s: %s\n",
343                        metadata->name, metadata->content);
344       }
345
346       ++ptr;
347     }
348
349     info_dialog_new (g_basename (sample->pathname), xifish_xpm,
350                      _("Decoding %s\n"
351                        "Encoded by: %s\n\n"
352                        "%s"),
353                      g_basename (sample->pathname),
354                      ov_comment(vf,-1)->vendor, buf);
355   }
356 #endif /* DEVEL_CODE */
357
358   schedule_operation (sample, buf, &vorbis_load_op, sample);
359
360   return sample;
361 }
362
363 sw_sample *
364 vorbis_sample_reload (sw_sample * sample)
365 {
366   if (sample == NULL) return NULL;
367
368   return sample_load_vorbis_info (sample, sample->pathname);
369 }
370
371 sw_sample *
372 vorbis_sample_load (char * pathname)
373 {
374   if (pathname == NULL) return NULL;
375
376   return sample_load_vorbis_info (NULL, pathname);
377 }
378
379 typedef struct {
380   gchar * pathname;
381   gboolean use_abr;
382   gfloat quality;
383   long max_bitrate;
384   long nominal_bitrate;
385   long min_bitrate;
386   long serialno;
387 } vorbis_save_options;
388
389 static int
390 vorbis_sample_save_thread (sw_op_instance * inst)
391 {
392   sw_sample * sample = inst->sample;
393   char * pathname = (char *)inst->do_data;
394
395   FILE * outfile;
396   sw_format * format;
397   sw_audio_t * d;
398   sw_framecount_t remaining, len, run_total;
399   sw_framecount_t nr_frames, cframes;
400   gint percent = 0;
401
402   vorbis_save_options * so;
403
404   ogg_stream_state os; /* take physical pages, weld into a logical
405                           stream of packets */
406   ogg_page         og; /* one Ogg bitstream page.  Vorbis packets are inside */
407   ogg_packet       op; /* one raw packet of data for decode */
408
409   vorbis_info      vi; /* struct that stores all the static vorbis bitstream
410                           settings */
411   vorbis_comment   vc; /* struct that stores all the user comments */
412
413   vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
414   vorbis_block     vb; /* local working space for packet->PCM decode */
415
416   int eos=0,ret;
417   float **pcm;
418   long i, j;
419
420   gboolean active = TRUE;
421
422   size_t n, bytes_written = 0;
423   double average_bitrate = 0.0;
424
425   struct stat statbuf;
426   int errno_save = 0;
427
428   if (sample == NULL) return -1;
429
430   so = (vorbis_save_options *)sample->file_info;
431
432   format = sample->sounddata->format;
433
434   nr_frames = sample->sounddata->nr_frames;
435   cframes = nr_frames / 100;
436   if (cframes == 0) cframes = 1;
437
438   remaining = nr_frames;
439   run_total = 0;
440
441   d = sample->sounddata->data;
442
443   if (!(outfile = fopen (pathname, "w"))) {
444     sweep_perror (errno, pathname);
445     return -1;
446   }
447
448   vorbis_info_init (&vi);
449
450   if (so->use_abr) {
451     printf ("%ld, %ld, %ld\n", so->max_bitrate, so->nominal_bitrate,
452             so->min_bitrate);
453     ret = vorbis_encode_init (&vi, format->channels, format->rate,
454                               so->max_bitrate, so->nominal_bitrate,
455                               so->min_bitrate);
456   } else {
457     ret = vorbis_encode_init_vbr (&vi, format->channels, format->rate,
458                                   so->quality /* quality: 0 to 1 */);
459   }
460
461   if (ret) {
462     switch (ret) {
463     case OV_EIMPL:
464       sample_set_tmp_message (sample, _("Unsupported encoding mode"));
465       break;
466     default:
467       sample_set_tmp_message (sample, _("Invalid encoding options"));
468     }
469     return -1;
470   }
471
472   vorbis_comment_init (&vc);
473   vorbis_comment_add_tag (&vc, "ENCODER",
474                           "Sweep " VERSION " (metadecks.org)");
475
476   /* set up the analysis state and auxiliary encoding storage */
477   vorbis_analysis_init (&vd, &vi);
478   vorbis_block_init (&vd, &vb);
479
480   /* set up our packet->stream encoder */
481   ogg_stream_init (&os, so->serialno);
482
483   /* Vorbis streams begin with three headers; the initial header (with
484      most of the codec setup parameters) which is mandated by the Ogg
485      bitstream spec.  The second header holds any comment fields.  The
486      third header holds the bitstream codebook.  We merely need to
487      make the headers, then pass them to libvorbis one at a time;
488      libvorbis handles the additional Ogg bitstream constraints */
489
490   {
491     ogg_packet header;
492     ogg_packet header_comm;
493     ogg_packet header_code;
494
495     vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
496     ogg_stream_packetin(&os,&header); /* automatically placed in its own
497                                          page */
498     ogg_stream_packetin(&os,&header_comm);
499     ogg_stream_packetin(&os,&header_code);
500
501         /* This ensures the actual
502          * audio data will start on a new page, as per spec
503          */
504         while(!eos){
505                 int result=ogg_stream_flush(&os,&og);
506                 if(result==0)break;
507
508           n = fwrite (og.header, 1, og.header_len, outfile);
509           n += fwrite (og.body, 1, og.body_len, outfile);
510
511           if (fflush (outfile) == 0) {
512             bytes_written += n;
513           } else {
514             errno_save = errno;
515             eos = 1; /* pffft -- this encoding wasn't going anywhere */
516           }
517         }
518   }
519
520   while (!eos) {
521     g_mutex_lock (sample->ops_mutex);
522    
523     if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
524       active = FALSE;
525     }
526
527     if (active == FALSE || remaining <= 0) {
528       /* Tell the library we're at end of stream so that it can handle   
529        * the last frame and mark end of stream in the output properly
530        */
531       vorbis_analysis_wrote (&vd, 0);
532     } else {
533       /* data to encode */
534
535       len = MIN (remaining, 1024);
536
537       /* expose the buffer to submit data */
538       pcm = vorbis_analysis_buffer (&vd, 1024);
539
540       /* uninterleave samples */
541       for (i = 0; i < format->channels; i++) {
542         for (j = 0; j < len; j++) {
543           pcm[i][j] = d[j*format->channels + i];
544         }
545       }
546
547       /* tell the library how much we actually submitted */
548       vorbis_analysis_wrote(&vd, len);
549
550       d += (len * format->channels);
551
552       remaining -= len;
553
554       run_total += len;
555       percent = run_total / cframes;
556       sample_set_progress_percent (sample, percent);
557     }
558
559     g_mutex_unlock (sample->ops_mutex);
560
561     /* vorbis does some data preanalysis, then divvies up blocks for
562        more involved (potentially parallel) processing.  Get a single
563        block for encoding now */
564     while(vorbis_analysis_blockout(&vd,&vb)==1){
565
566       /* analysis, assume we want to use bitrate management */
567       vorbis_analysis(&vb,NULL);
568       vorbis_bitrate_addblock(&vb);
569
570       while(vorbis_bitrate_flushpacket(&vd,&op)){
571
572         /* weld the packet into the bitstream */
573         ogg_stream_packetin(&os,&op);
574
575         /* write out pages (if any) */
576         while(!eos){
577           int result=ogg_stream_pageout(&os,&og);
578           if(result==0)break;
579
580           n = fwrite (og.header, 1, og.header_len, outfile);
581           n += fwrite (og.body, 1, og.body_len, outfile);
582
583           if (fflush (outfile) == 0) {
584             bytes_written += n;
585           } else {
586             errno_save = errno;
587             active = FALSE;
588           }
589
590           /* this could be set above, but for illustrative purposes, I do
591              it here (to show that vorbis does know where the stream ends) */
592           if(ogg_page_eos(&og))eos=1;
593         }
594       }
595     }
596   }
597
598   /* clean up and exit.  vorbis_info_clear() must be called last */
599  
600   ogg_stream_clear(&os);
601   vorbis_block_clear(&vb);
602   vorbis_dsp_clear(&vd);
603   vorbis_comment_clear(&vc);
604   vorbis_info_clear(&vi);
605
606   fclose (outfile);
607
608   /* Report success or failure; Calculate and display statistics */
609
610   if (remaining <= 0) {
611     char time_buf[16], bytes_buf[16];
612
613     sample_store_and_free_pathname (sample, pathname);
614
615     /* Mark the last mtime for this sample */
616
617     stat (sample->pathname, &statbuf);
618     sample->last_mtime = statbuf.st_mtime;
619     sample->edit_ignore_mtime = FALSE;
620     sample->modified = FALSE;
621
622     snprint_time (time_buf, sizeof (time_buf),
623                   frames_to_time (format, nr_frames - remaining));
624
625     snprint_bytes (bytes_buf, sizeof (bytes_buf), bytes_written);
626
627     average_bitrate =
628       8.0/1000.0*((double)bytes_written/((double)nr_frames/(double)format->rate));
629    
630     info_dialog_new (_("Ogg Vorbis encoding results"), xifish_xpm,
631                      "Encoding of %s succeeded.\n\n"
632                      "%s written, %s audio\n"
633                      "Average bitrate: %.1f kbps",
634                      g_basename (sample->pathname),
635                      bytes_buf, time_buf,
636                      average_bitrate);
637   } else {
638     char time_buf[16], bytes_buf[16];
639
640     snprint_time (time_buf, sizeof (time_buf),
641                   frames_to_time (format, nr_frames - remaining));
642
643     snprint_bytes (bytes_buf, sizeof (bytes_buf), bytes_written);
644
645     average_bitrate =
646       8.0/1000.0*((double)bytes_written/((double)(nr_frames - remaining)/(double)format->rate));
647     if (isnan(average_bitrate)) average_bitrate = 0.0;
648
649     if (errno_save == 0) {
650       info_dialog_new (_("Ogg Vorbis encoding results"), xifish_xpm,
651                        "Encoding of %s FAILED\n\n"
652                        "%s written, %s audio (%d%% complete)\n"
653                        "Average bitrate: %.1f kbps",
654                        g_basename (pathname), bytes_buf, time_buf, percent,
655                        average_bitrate);
656     } else {
657       sweep_perror (errno_save,
658                     "Encoding of %s FAILED\n\n"
659                     "%s written, %s audio (%d%% complete)\n"
660                     "Average bitrate: %.1f kbps",
661                     g_basename (pathname), bytes_buf, time_buf, percent,
662                     average_bitrate);
663     }
664   }
665
666
667   sample_set_edit_state (sample, SWEEP_EDIT_STATE_DONE);
668
669   return 0;
670 }
671
672 static sw_operation vorbis_save_op = {
673   SWEEP_EDIT_MODE_META,
674   (SweepCallback)vorbis_sample_save_thread,
675   (SweepFunction)NULL,
676   (SweepCallback)NULL, /* undo */
677   (SweepFunction)NULL,
678   (SweepCallback)NULL, /* redo */
679   (SweepFunction)NULL
680 };
681
682 int
683 vorbis_sample_save (sw_sample * sample, char * pathname)
684 {
685   char buf[64];
686
687   g_snprintf (buf, sizeof (buf), _("Saving %s"), g_basename (pathname));
688
689   schedule_operation (sample, buf, &vorbis_save_op, pathname);
690
691   return 0;
692 }
693
694 static void
695 vorbis_save_options_dialog_ok_cb (GtkWidget * widget, gpointer data)
696 {
697   sw_sample * sample = (sw_sample *)data;
698   GtkWidget * dialog;
699   vorbis_save_options * so;
700   GtkWidget * checkbutton;
701   GtkWidget * entry;
702   const gchar * text;
703
704   gboolean use_abr;
705   GtkObject * quality_adj;
706   gfloat quality = -1.0;
707   long max_bitrate = -1, nominal_bitrate = -1, min_bitrate = -1;
708   gboolean rem_encode;
709   long serialno;
710   gboolean rem_serialno;
711
712   char * pathname;
713
714   so = g_malloc (sizeof(vorbis_save_options));
715
716   dialog = gtk_widget_get_toplevel (widget);
717
718   checkbutton =
719     GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "abr_chb"));
720   use_abr =
721     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(checkbutton)); 
722
723   if (use_abr) {
724     entry = GTK_WIDGET(g_object_get_data (G_OBJECT(dialog),
725                                            "nominal_bitrate_entry"));
726     text = gtk_entry_get_text (GTK_ENTRY(entry));
727     nominal_bitrate = strtol (text, (char **)NULL, 0);
728     if (nominal_bitrate == LONG_MIN || nominal_bitrate == LONG_MAX ||
729         nominal_bitrate == 0)
730       nominal_bitrate = DEFAULT_NOMINAL;
731
732     entry = GTK_WIDGET(g_object_get_data (G_OBJECT(dialog),
733                                            "max_bitrate_entry"));
734     text = gtk_entry_get_text (GTK_ENTRY(entry));
735     max_bitrate = strtol (text, (char **)NULL, 0);
736     if (max_bitrate == LONG_MIN || max_bitrate == LONG_MAX ||
737         max_bitrate == 0)
738       max_bitrate = -1;
739
740     entry = GTK_WIDGET(g_object_get_data (G_OBJECT(dialog),
741                                            "min_bitrate_entry"));
742     text = gtk_entry_get_text (GTK_ENTRY(entry));
743     min_bitrate = strtol (text, (char **)NULL, 0);
744     if (min_bitrate == LONG_MIN || min_bitrate == LONG_MAX ||
745         min_bitrate == 0)
746       min_bitrate = -1;
747
748   } else {
749     quality_adj =
750       GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "quality_adj"));
751     quality = GTK_ADJUSTMENT(quality_adj)->value;
752   }
753
754   checkbutton =
755     GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "rem_encode_chb"));
756   rem_encode =
757     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(checkbutton));
758
759   entry =
760     GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "serialno_entry"));
761   text = gtk_entry_get_text (GTK_ENTRY(entry));
762   serialno = strtol (text, (char **)NULL, 0);
763   if (serialno == LONG_MIN || serialno == LONG_MAX) serialno = random ();
764
765   checkbutton =
766     GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "rem_serialno_chb"));
767   rem_serialno =
768     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(checkbutton));
769
770   pathname = g_object_get_data (G_OBJECT(dialog), "pathname");
771
772   gtk_widget_destroy (dialog);
773
774   if (rem_encode) {
775     prefs_set_int (ABR_KEY, use_abr);
776     if (use_abr) {
777       prefs_set_long (NOMINAL_KEY, nominal_bitrate);
778       prefs_set_long (MAXIMUM_KEY, max_bitrate);
779       prefs_set_long (MINIMUM_KEY, min_bitrate);
780     } else {
781       prefs_set_float (QUALITY_KEY, quality);
782     }
783   }
784
785   if (rem_serialno) {
786     prefs_set_long (SERIALNO_KEY, serialno);
787   } else {
788     prefs_delete (SERIALNO_KEY);
789   }
790
791   if (sample->file_info) {
792     g_free (sample->file_info);
793   }
794
795   so->use_abr = use_abr;
796
797   if (use_abr) {
798     if (max_bitrate > 0) max_bitrate *= 1000;
799     nominal_bitrate *= 1000;
800     if (min_bitrate > 0) min_bitrate *= 1000;
801
802     so->max_bitrate = max_bitrate;
803     so->nominal_bitrate = nominal_bitrate;
804     so->min_bitrate = min_bitrate;
805   } else {
806     g_assert (quality != -1.0);
807     so->quality = quality / 10.0;
808   }
809
810   so->serialno = serialno;
811
812   sample->file_info = so; 
813
814   vorbis_sample_save (sample, pathname);
815 }
816
817 static void
818 vorbis_save_options_dialog_cancel_cb (GtkWidget * widget, gpointer data)
819 {
820   GtkWidget * dialog;
821
822   dialog = gtk_widget_get_toplevel (widget);
823   gtk_widget_destroy (dialog);
824
825   /* if the sample bank is empty, quit the program */
826   sample_bank_remove (NULL);
827 }
828
829 static void
830 bitrate_enable_cb (GtkWidget * widget, gpointer data)
831 {
832   GtkWidget * bitrate_widget = (GtkWidget *)data;
833   GtkWidget * quality_widget;
834   gboolean active;
835
836   quality_widget = g_object_get_data (G_OBJECT(widget), "quality_widget");
837
838   active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget));
839
840   gtk_widget_set_sensitive (quality_widget, !active);
841   gtk_widget_set_sensitive (bitrate_widget, active);
842 }
843
844 static void
845 vorbis_encode_options_reset_cb (GtkWidget * widget, gpointer data)
846 {
847   GtkWidget * dialog;
848   GtkWidget * checkbutton;
849   GtkWidget * entry;
850
851   int * i;
852   gboolean use_abr;
853   GtkObject * quality_adj;
854   float * q, quality;
855   long * l, bitrate;
856
857   dialog = gtk_widget_get_toplevel (widget);
858
859   /* Quality */
860
861   quality_adj =
862     GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "quality_adj"));
863  
864   q = prefs_get_float (QUALITY_KEY);
865  
866   if (q == NULL) {
867     quality = DEFAULT_QUALITY;
868   } else {
869     quality = *q;
870   }
871  
872   gtk_adjustment_set_value (GTK_ADJUSTMENT(quality_adj), quality);
873
874   /* Nominal bitrate */
875
876   entry = GTK_WIDGET(g_object_get_data (G_OBJECT(dialog),
877                                          "nominal_bitrate_entry"));
878   l = prefs_get_long (NOMINAL_KEY);
879   if (l == NULL) {
880     bitrate = DEFAULT_NOMINAL;
881   } else {
882     bitrate = *l;
883   }
884   gtk_entry_set_text (GTK_ENTRY (entry), g_strdup_printf ("%ld", bitrate));
885
886   /* Max bitrate */
887
888   entry = GTK_WIDGET(g_object_get_data (G_OBJECT(dialog),
889                                          "max_bitrate_entry"));
890   l = prefs_get_long (MAXIMUM_KEY);
891   if (l != NULL && (*l != -1)) {
892     gtk_entry_set_text (GTK_ENTRY (entry), g_strdup_printf ("%ld", *l));
893   }
894
895   /* Min bitrate */
896  
897   entry = GTK_WIDGET(g_object_get_data (G_OBJECT(dialog),
898                                          "min_bitrate_entry"));
899   l = prefs_get_long (MINIMUM_KEY);
900   if (l != NULL && (*l != -1)) {
901     gtk_entry_set_text (GTK_ENTRY (entry), g_strdup_printf ("%ld", *l));
902   }
903
904   /* Use ABR */
905
906   i = prefs_get_int (ABR_KEY);
907   if (i == NULL) {
908     use_abr = FALSE;
909   } else {
910     use_abr = (gboolean) *i;
911   }
912
913   checkbutton =
914     GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "abr_chb"));
915   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), use_abr);
916 }
917
918 static void
919 vorbis_encode_options_default_cb (GtkWidget * widget, gpointer data)
920 {
921   GtkWidget * dialog;
922   GtkWidget * checkbutton;
923   GtkWidget * entry;
924
925   GtkObject * quality_adj;
926
927   dialog = gtk_widget_get_toplevel (widget);
928
929   /* Quality */
930
931   quality_adj =
932     GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "quality_adj"));
933   gtk_adjustment_set_value (GTK_ADJUSTMENT(quality_adj), DEFAULT_QUALITY);
934
935   /* Nominal bitrate */
936
937   entry = GTK_WIDGET(g_object_get_data (G_OBJECT(dialog),
938                                          "nominal_bitrate_entry"));
939   gtk_entry_set_text (GTK_ENTRY (entry),
940                       g_strdup_printf ("%ld", DEFAULT_NOMINAL));
941
942   /* Max bitrate */
943
944   entry = GTK_WIDGET(g_object_get_data (G_OBJECT(dialog),
945                                          "max_bitrate_entry"));
946   gtk_entry_set_text (GTK_ENTRY (entry), "");
947
948   /* Min bitrate */
949  
950   entry = GTK_WIDGET(g_object_get_data (G_OBJECT(dialog),
951                                          "min_bitrate_entry"));
952   gtk_entry_set_text (GTK_ENTRY (entry), "");
953
954   /* Use ABR */
955
956   checkbutton =
957     GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "abr_chb"));
958   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), FALSE);
959 }
960
961 #ifdef DEVEL_CODE
962 static void
963 metadata_table_add_row (GtkWidget * table, int row, char * title, char * tip)
964 {
965   GtkWidget * hbox;
966   GtkWidget * label;
967   GtkWidget * entry;
968   GtkTooltips * tooltips;
969
970   hbox = gtk_hbox_new (FALSE, 0);
971   gtk_table_attach (GTK_TABLE(table), hbox, 0, 1, row, row+1,
972                     GTK_FILL, GTK_SHRINK, 0, 0);
973   gtk_widget_show (hbox);
974  
975   label = gtk_label_new (title);
976   gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
977   gtk_widget_show (label);
978
979   entry = gtk_entry_new ();
980   gtk_table_attach (GTK_TABLE(table), entry, 1, 2, row, row+1,
981                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
982   gtk_widget_show (entry);
983
984   tooltips = gtk_tooltips_new ();
985   gtk_tooltips_set_tip (tooltips, entry, tip, NULL);
986 }
987 #endif
988
989 static void
990 remember_serialno_clicked_cb (GtkWidget * widget, gpointer data)
991 {
992   sw_sample * sample = (sw_sample *)data;
993   gboolean active;
994
995   active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget));
996
997   if (active) {
998     sample_set_tmp_message (sample, _("Hack the planet!"));
999   } else {
1000     sample_clear_tmp_message (sample);
1001   }
1002 }
1003
1004 static gboolean
1005 randomise_serialno (gpointer data)
1006 {
1007   GtkWidget * entry = (GtkWidget *)data;
1008   gchar * new_text;
1009
1010   new_text = g_strdup_printf ("%ld", random ());
1011   gtk_entry_set_text (GTK_ENTRY (entry), new_text);
1012   g_free (new_text);
1013
1014   return TRUE;
1015 }
1016
1017 static void
1018 randomise_serialno_pressed_cb (GtkWidget * widget, gpointer data)
1019 {
1020   GtkWidget * dialog;
1021   GtkWidget * checkbutton;
1022   gint tag;
1023
1024   dialog = gtk_widget_get_toplevel (widget);
1025
1026   checkbutton =
1027     GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "rem_serialno_chb"));
1028   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), FALSE);
1029
1030   tag = g_timeout_add (30, randomise_serialno, data);
1031   g_object_set_data (G_OBJECT(widget), "tag", GINT_TO_POINTER(tag));
1032 }
1033
1034 static void
1035 randomise_serialno_released_cb (GtkWidget * widget, gpointer data)
1036 {
1037   gint tag;
1038
1039   tag = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(widget), "tag"));
1040   g_source_remove (tag);
1041 }
1042
1043 static GtkWidget *
1044 create_vorbis_encoding_options_dialog (sw_sample * sample, char * pathname)
1045 {
1046   GtkWidget * dialog;
1047   GtkWidget * ok_button, * button;
1048   GtkWidget * main_vbox;
1049   GtkWidget * ebox;
1050   GtkWidget * vbox;
1051   GtkWidget * hbox, * hbox2;
1052   GtkWidget * label;
1053   GtkWidget * pixmap;
1054
1055   GtkWidget * notebook;
1056
1057   GtkWidget * checkbutton; 
1058   GtkWidget * frame;
1059   GtkObject * quality_adj;
1060   GtkWidget * quality_hscale;
1061   GtkWidget * table;
1062   GtkWidget * entry;
1063   GtkTooltips * tooltips;
1064
1065   long * l;
1066
1067 #ifdef DEVEL_CODE /* metadata */
1068   int t; /* table row */
1069   GtkWidget * scrolled;
1070 #endif
1071
1072   dialog = gtk_dialog_new ();
1073   gtk_window_set_title (GTK_WINDOW(dialog),
1074                         _("Sweep: Ogg Vorbis save options"));
1075   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
1076
1077   attach_window_close_accel(GTK_WINDOW(dialog));
1078
1079   g_object_set_data (G_OBJECT(dialog), "pathname", pathname);
1080
1081   main_vbox = GTK_DIALOG(dialog)->vbox;
1082
1083   ebox = gtk_event_box_new ();
1084   gtk_box_pack_start (GTK_BOX(main_vbox), ebox, TRUE, TRUE, 0);
1085   gtk_widget_set_style (ebox, style_bw);
1086   gtk_widget_show (ebox);
1087
1088   vbox = gtk_vbox_new (FALSE, 0);
1089   gtk_container_add (GTK_CONTAINER(ebox), vbox);
1090   gtk_widget_show (vbox);
1091
1092   /* Ogg Vorbis pixmaps */
1093
1094   hbox = gtk_hbox_new (FALSE, 0);
1095   gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1096   gtk_container_set_border_width (GTK_CONTAINER(hbox), 4);
1097   gtk_widget_show (hbox);
1098
1099   pixmap = create_widget_from_xpm (dialog, white_ogg_xpm);
1100   gtk_box_pack_start (GTK_BOX(hbox), pixmap, FALSE, FALSE, 0);
1101   gtk_widget_show (pixmap);
1102
1103   pixmap = create_widget_from_xpm (dialog, vorbisword2_xpm);
1104   gtk_box_pack_start (GTK_BOX(hbox), pixmap, FALSE, FALSE, 0);
1105   gtk_widget_show (pixmap);
1106
1107   /* filename */
1108
1109   hbox = gtk_hbox_new (FALSE, 0);
1110   gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1111   gtk_container_set_border_width (GTK_CONTAINER(hbox), 4);
1112   gtk_widget_show (hbox);
1113 /* pangoise?
1114
1115  style = gtk_style_new ();
1116  gdk_font_unref (style->font);
1117  style->font =
1118  gdk_font_load("-*-helvetica-medium-r-normal-*-*-180-*-*-*-*-*-*");
1119  gtk_widget_push_style (style);
1120 */
1121   label = gtk_label_new (g_basename (pathname));
1122   gtk_box_pack_start (GTK_BOX(hbox), label, TRUE, FALSE, 0);
1123   gtk_widget_show (label);
1124  
1125 /* gtk_widget_pop_style ();*/
1126
1127   notebook = gtk_notebook_new ();
1128   gtk_box_pack_start (GTK_BOX(main_vbox), notebook, TRUE, TRUE, 4);
1129   gtk_widget_show (notebook);
1130
1131   /* Encoding quality */
1132
1133   label = gtk_label_new (_("Vorbis encoding"));
1134
1135   vbox = gtk_vbox_new (FALSE, 0);
1136   gtk_notebook_append_page (GTK_NOTEBOOK(notebook), vbox, label);
1137   gtk_container_set_border_width (GTK_CONTAINER(vbox), 4);
1138   gtk_widget_show (vbox);
1139
1140   hbox = gtk_hbox_new (FALSE, 4);
1141   gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 4);
1142   gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);
1143   gtk_widget_show (hbox);
1144
1145   label = gtk_label_new (_("Encoding quality:"));
1146   gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 4);
1147   gtk_widget_show (label);
1148
1149   quality_adj = gtk_adjustment_new (DEFAULT_QUALITY, /* value */
1150                                     0.1, /* lower */
1151                                     10.0, /* upper */
1152                                     0.001, /* step incr */
1153                                     0.001, /* page incr */
1154                                     0.001  /* page size */
1155                                     );
1156
1157   {
1158     /* How sucky ... we create a vbox in order to center the hscale within
1159      * its allocation, thus actually lining it up with its label ...
1160      */
1161     GtkWidget * vbox_pants;
1162
1163     vbox_pants = gtk_vbox_new (FALSE, 0);
1164     gtk_box_pack_start (GTK_BOX(hbox), vbox_pants, TRUE, TRUE, 0);
1165     gtk_widget_show (vbox_pants);
1166
1167     quality_hscale = gtk_hscale_new (GTK_ADJUSTMENT(quality_adj));
1168     gtk_box_pack_start (GTK_BOX (vbox_pants), quality_hscale, TRUE, TRUE, 0);
1169     gtk_scale_set_draw_value (GTK_SCALE (quality_hscale), TRUE);
1170     gtk_widget_set_size_request (quality_hscale, gdk_screen_width() / 8, -1);
1171     gtk_widget_show (quality_hscale);
1172
1173     label = gtk_label_new (NULL);
1174     gtk_box_pack_start (GTK_BOX(vbox_pants), label, FALSE, FALSE, 0);
1175     gtk_widget_show (label);
1176   }
1177
1178   tooltips = gtk_tooltips_new ();
1179   gtk_tooltips_set_tip (tooltips, quality_hscale,
1180                         _("Encoding quality between 0 (lowest quality, "
1181                           "smallest file) and 10 (highest quality, largest "
1182                           "file) using variable bitrate mode (VBR)."),
1183                         NULL);
1184
1185   g_object_set_data (G_OBJECT (dialog), "quality_adj", quality_adj);
1186
1187   /* Bitrate management (ABR) */
1188
1189   checkbutton =
1190     gtk_check_button_new_with_label (_("Enable bitrate management engine"));
1191   gtk_box_pack_start (GTK_BOX(vbox), checkbutton, FALSE, FALSE, 4);
1192   gtk_widget_show (checkbutton);
1193
1194   tooltips = gtk_tooltips_new ();
1195   gtk_tooltips_set_tip (tooltips, checkbutton,
1196                         _("This enables average bitrate mode (ABR). You must "
1197                           "suggest a nominal average bitrate and may specify "
1198                           "minimum and maximum bounds.\n"
1199                           "For best results it is generally recommended that "
1200                           "you use the variable bitrate 'encoding quality' "
1201                           "control (above) instead."),
1202                         NULL);
1203
1204   g_object_set_data (G_OBJECT(checkbutton), "quality_widget", hbox);
1205  
1206   frame = gtk_frame_new (_("Bitrate management engine"));
1207   gtk_box_pack_start (GTK_BOX(vbox), frame, TRUE, TRUE, 4);
1208   gtk_container_set_border_width (GTK_CONTAINER(frame), 12);
1209   gtk_widget_show (frame);
1210
1211   table = gtk_table_new (3, 3, FALSE);
1212   gtk_table_set_row_spacings (GTK_TABLE(table), 8);
1213   gtk_table_set_col_spacings (GTK_TABLE(table), 8);
1214   gtk_container_add (GTK_CONTAINER(frame), table);
1215   gtk_container_set_border_width (GTK_CONTAINER(table), 8);
1216   gtk_widget_show (table);
1217
1218   g_signal_connect (G_OBJECT(checkbutton), "toggled",
1219                       G_CALLBACK(bitrate_enable_cb), frame);
1220
1221   g_object_set_data (G_OBJECT (dialog), "abr_chb", checkbutton);
1222
1223   gtk_widget_set_sensitive (frame, FALSE);
1224
1225   /* Nominal bitrate */
1226
1227   hbox = gtk_hbox_new (FALSE, 0);
1228   gtk_table_attach (GTK_TABLE(table), hbox, 0, 1, 0, 1,
1229                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1230   gtk_widget_show (hbox);
1231  
1232   label = gtk_label_new (_("Nominal bitrate (ABR):"));
1233   gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
1234   gtk_widget_show (label);
1235
1236   entry = gtk_entry_new ();
1237   gtk_table_attach (GTK_TABLE(table), entry, 1, 2, 0, 1,
1238                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1239   gtk_widget_show (entry);
1240
1241   g_object_set_data (G_OBJECT (dialog), "nominal_bitrate_entry", entry);
1242
1243   tooltips = gtk_tooltips_new ();
1244   gtk_tooltips_set_tip (tooltips, entry,
1245                         _("Specify a nominal bitrate. Attempt to "
1246                           "encode at a bitrate averaging this."),
1247                         NULL);
1248
1249   label = gtk_label_new (_("kbps"));
1250   gtk_table_attach (GTK_TABLE(table), label, 2, 3, 0, 1,
1251                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1252   gtk_widget_show (label);
1253
1254   /* Minimum bitrate */
1255
1256   hbox = gtk_hbox_new (FALSE, 0);
1257   gtk_table_attach (GTK_TABLE(table), hbox, 0, 1, 1, 2,
1258                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1259   gtk_widget_show (hbox);
1260  
1261   label = gtk_label_new (_("Minimum bitrate:"));
1262   gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
1263   gtk_widget_show (label);
1264
1265   entry = gtk_entry_new ();
1266   gtk_table_attach (GTK_TABLE(table), entry, 1, 2, 1, 2,
1267                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1268   gtk_widget_show (entry);
1269
1270   g_object_set_data (G_OBJECT (dialog), "min_bitrate_entry", entry);
1271
1272   tooltips = gtk_tooltips_new ();
1273   gtk_tooltips_set_tip (tooltips, entry,
1274                         _("Specify a minimum bitrate, useful for "
1275                           "encoding for a fixed-size channel. (Optional)"),
1276                         NULL);
1277
1278   label = gtk_label_new (_("kbps"));
1279   gtk_table_attach (GTK_TABLE(table), label, 2, 3, 1, 2,
1280                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1281   gtk_widget_show (label);
1282
1283
1284   /* Maximum bitrate */
1285
1286   hbox = gtk_hbox_new (FALSE, 0);
1287   gtk_table_attach (GTK_TABLE(table), hbox, 0, 1, 2, 3,
1288                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1289   gtk_widget_show (hbox);
1290  
1291   label = gtk_label_new (_("Maximum bitrate:"));
1292   gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
1293   gtk_widget_show (label);
1294
1295   entry = gtk_entry_new ();
1296   gtk_table_attach (GTK_TABLE(table), entry, 1, 2, 2, 3,
1297                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1298   gtk_widget_show (entry);
1299
1300   g_object_set_data (G_OBJECT (dialog), "max_bitrate_entry", entry);
1301
1302   tooltips = gtk_tooltips_new ();
1303   gtk_tooltips_set_tip (tooltips, entry,
1304                         _("Specify a maximum bitrate, useful for "
1305                           "streaming applications. (Optional)"),
1306                         NULL);
1307
1308   label = gtk_label_new (_("kbps"));
1309   gtk_table_attach (GTK_TABLE(table), label, 2, 3, 2, 3,
1310                     GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1311   gtk_widget_show (label);
1312
1313   /* Remember / Reset */
1314
1315   hbox = gtk_hbox_new (FALSE, 4);
1316   gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 4);
1317   gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);
1318   gtk_widget_show (hbox);
1319
1320   checkbutton =
1321     gtk_check_button_new_with_label (_("Remember these encoding options"));
1322   gtk_box_pack_start (GTK_BOX (hbox), checkbutton, TRUE, TRUE, 0);
1323   gtk_widget_show (checkbutton);
1324
1325   g_object_set_data (G_OBJECT (dialog), "rem_encode_chb", checkbutton);
1326
1327   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), TRUE);
1328
1329   hbox2 = gtk_hbox_new (TRUE, 4);
1330   gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, TRUE, 0);
1331   gtk_widget_show (hbox2);
1332
1333   button = gtk_button_new_with_label (_("Reset"));
1334   gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, TRUE, 4);
1335   g_signal_connect (G_OBJECT(button), "clicked",
1336                       G_CALLBACK(vorbis_encode_options_reset_cb), NULL);
1337   gtk_widget_show (button);
1338
1339   tooltips = gtk_tooltips_new ();
1340   gtk_tooltips_set_tip (tooltips, button,
1341                         _("Reset to the last remembered encoding options."),
1342                         NULL);
1343
1344   /* Call the reset callback now to set remembered options */
1345   vorbis_encode_options_reset_cb (button, NULL);
1346
1347   button = gtk_button_new_with_label (_("Defaults"));
1348   gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, TRUE, 4);
1349   g_signal_connect (G_OBJECT(button), "clicked",
1350                       G_CALLBACK(vorbis_encode_options_default_cb), NULL);
1351   gtk_widget_show (button);
1352
1353   tooltips = gtk_tooltips_new ();
1354   gtk_tooltips_set_tip (tooltips, button,
1355                         _("Set to default encoding options."),
1356                         NULL);
1357
1358 #ifdef DEVEL_CODE
1359
1360   /* Metadata */
1361
1362   label = gtk_label_new (_("Metadata"));
1363
1364   scrolled = gtk_scrolled_window_new (NULL, NULL);
1365   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1366                                   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1367   gtk_notebook_append_page (GTK_NOTEBOOK(notebook), scrolled, label);
1368   gtk_widget_show (scrolled);
1369
1370   t = 0;
1371
1372   table = gtk_table_new (1, 2, FALSE);
1373   gtk_table_set_row_spacings (GTK_TABLE(table), 8);
1374   gtk_table_set_col_spacings (GTK_TABLE(table), 8);
1375   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
1376                                          table);
1377   gtk_container_set_border_width (GTK_CONTAINER(table), 8);
1378   gtk_widget_show (table);
1379
1380   /* These fields and descriptions derived from libvorbis API documentation:
1381    * /usr/share/doc/libvorbis-dev/v-comment.html
1382    */
1383
1384   metadata_table_add_row (table, t++, _("Title:"), _("Track/Work name"));
1385
1386   metadata_table_add_row (table, t++, _("Version:"),
1387                           _("The version field may be used to differentiate "
1388                             "multiple versions of the same track title in a "
1389                             "single collection. (e.g. remix info)"));
1390
1391   metadata_table_add_row (table, t++, _("Album:"),
1392                           _("The collection name to which this track belongs"));
1393
1394   metadata_table_add_row (table, t++, _("Artist:"),
1395                           _("The artist generally considered responsible for "
1396                             "the work. In popular music this is usually the "
1397                             "performing band or singer. For classical music "
1398                             "it would be the composer. For an audio book it "
1399                             "would be the author of the original text."));
1400
1401   metadata_table_add_row (table, t++, _("Performer:"),
1402                           _("The artist(s) who performed the work. In "
1403                             "classical music this would be the conductor, "
1404                             "orchestra, soloists. In an audio book it would "
1405                             "be the actor who did the reading. In popular "
1406                             "music this is typically the same as the ARTIST "
1407                             "and is omitted."));
1408
1409   metadata_table_add_row (table, t++, _("Copyright:"),
1410                           _("Copyright attribution, e.g., '2001 Nobody's "
1411                             "Band' or '1999 Jack Moffitt'"));
1412
1413   metadata_table_add_row (table, t++, _("License:"),
1414                           _("License information, eg, 'All Rights Reserved', "
1415                             "'Any Use Permitted', a URL to a license such as "
1416                             "a Creative Commons license "
1417                             "(\"www.creativecommons.org/blahblah/license.html\") "
1418                             "or the EFF Open Audio License ('distributed "
1419                             "under the terms of the Open Audio License. see "
1420                             "http://www.eff.org/IP/Open_licenses/eff_oal.html "
1421                             "for details'), etc."));
1422
1423   metadata_table_add_row (table, t++, _("Organization:"),
1424                           _("Name of the organization producing the track "
1425                             "(i.e. the 'record label')"));
1426
1427   metadata_table_add_row (table, t++, _("Description:"),
1428                           _("A short text description of the contents"));
1429
1430   metadata_table_add_row (table, t++, _("Genre:"),
1431                           _("A short text indication of music genre"));
1432
1433   metadata_table_add_row (table, t++, _("Date:"),
1434                           _("Date the track was recorded"));
1435
1436   metadata_table_add_row (table, t++, _("Location:"),
1437                           _("Location where track was recorded"));
1438
1439   metadata_table_add_row (table, t++, _("Contact:"),
1440                           _("Contact information for the creators or "
1441                             "distributors of the track. This could be a URL, "
1442                             "an email address, the physical address of the "
1443                             "producing label."));
1444
1445   metadata_table_add_row (table, t++, _("ISRC:"),
1446                           _("ISRC number for the track; see the ISRC intro "
1447                             "page (http://www.ifpi.org/site-content/online/isrc_intro.html) "
1448                             "for more information on ISRC numbers."));
1449
1450 #endif /* DEVEL_CODE */
1451
1452   /* Ogg stream */
1453
1454   label = gtk_label_new (_("Ogg stream"));
1455
1456   vbox = gtk_vbox_new (FALSE, 4);
1457   gtk_notebook_append_page (GTK_NOTEBOOK(notebook), vbox, label);
1458   gtk_widget_show (vbox);
1459
1460   /* Stream serial no. */
1461
1462   hbox = gtk_hbox_new (FALSE, 0);
1463   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1464   gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);
1465   gtk_widget_show (hbox);
1466
1467   label = gtk_label_new (_("Ogg stream serial number:"));
1468   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
1469   gtk_widget_show (label);
1470
1471   entry = gtk_entry_new ();
1472   gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 4);
1473   gtk_widget_show (entry);
1474
1475   g_object_set_data (G_OBJECT (dialog), "serialno_entry", entry);
1476
1477   /* Remember serialno ? */
1478
1479   hbox = gtk_hbox_new (FALSE, 0);
1480   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1481   gtk_widget_show (hbox);
1482
1483   button = gtk_hseparator_new ();
1484   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 8);
1485   gtk_widget_show (button);
1486
1487   checkbutton =
1488     gtk_check_button_new_with_label (_("Remember this serial number"));
1489   gtk_box_pack_start (GTK_BOX (hbox), checkbutton, FALSE, TRUE, 0);
1490   gtk_widget_show (checkbutton);
1491
1492   g_signal_connect (G_OBJECT(checkbutton), "toggled",
1493                       G_CALLBACK(remember_serialno_clicked_cb),
1494                       sample);
1495
1496   tooltips = gtk_tooltips_new ();
1497   gtk_tooltips_set_tip (tooltips, checkbutton,
1498                         _("Remember this serial number for future re-use.\n"
1499                           "USE OF THIS OPTION IS NOT RECOMMENDED.\n"
1500                           "Each encoded file should have a different "
1501                           "serial number; "
1502                           "re-use of Ogg serial numbers in different files "
1503                           "may create incompatabilities with streaming "
1504                           "applications. "
1505                           "This option is provided for bitstream engineering "
1506                           "purposes only.\n"
1507                           "If this option is not checked, new serial numbers "
1508                           "will be randomly generated for each file encoded."),
1509                         NULL);
1510
1511   g_object_set_data (G_OBJECT (dialog), "rem_serialno_chb", checkbutton);
1512
1513   l = prefs_get_long (SERIALNO_KEY);
1514
1515   if (l == NULL) {
1516     randomise_serialno (entry);
1517     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), FALSE);
1518   } else {
1519     gtk_entry_set_text (GTK_ENTRY(entry), g_strdup_printf ("%ld", *l));
1520     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), TRUE);
1521   }
1522
1523   /* Randomise serialno! */
1524
1525   button = gtk_button_new_with_label (_("Randomize!"));
1526   gtk_container_set_border_width (GTK_CONTAINER(button), 64);
1527   gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
1528   gtk_widget_show (button);
1529
1530   tooltips = gtk_tooltips_new ();
1531   gtk_tooltips_set_tip (tooltips, button,
1532                         _("Generate a random serial number for the "
1533                           "Ogg bitstream. The number will change while "
1534                           "this button is held down."),
1535                         NULL);
1536
1537   g_signal_connect (G_OBJECT(button), "pressed",
1538                       G_CALLBACK(randomise_serialno_pressed_cb),
1539                       entry);
1540
1541   g_signal_connect (G_OBJECT(button), "released",
1542                       G_CALLBACK(randomise_serialno_released_cb),
1543                       entry);
1544
1545   /* About */
1546
1547   label = gtk_label_new (_("About"));
1548
1549   ebox = gtk_event_box_new ();
1550   gtk_notebook_append_page (GTK_NOTEBOOK(notebook), ebox, label);
1551   gtk_widget_set_style (ebox, style_bw);
1552   gtk_widget_show (ebox);
1553
1554   gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK(notebook), ebox,
1555                                       TRUE, TRUE, GTK_PACK_END);
1556
1557   vbox = gtk_vbox_new (FALSE, 16);
1558   gtk_container_add (GTK_CONTAINER(ebox), vbox);
1559   gtk_container_set_border_width (GTK_CONTAINER(vbox), 8);
1560   gtk_widget_show (vbox);
1561  
1562   label =
1563     gtk_label_new (_("Ogg Vorbis is a high quality general purpose\n"
1564                      "perceptual audio codec. It is free, open and\n"
1565                      "unpatented."));
1566   gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
1567   gtk_widget_show (label);
1568
1569   hbox = gtk_hbox_new (FALSE, 16);
1570   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
1571   gtk_widget_show (hbox);
1572
1573   label =
1574     gtk_label_new (_("Ogg, Vorbis, Xiph.org Foundation and their logos\n"
1575                      "are trademarks (tm) of the Xiph.org Foundation.\n"
1576                      "Used with permission."));
1577   gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 8);
1578   gtk_widget_show (label);
1579
1580   pixmap = create_widget_from_xpm (dialog, xifish_xpm);
1581   gtk_box_pack_start (GTK_BOX(hbox), pixmap, FALSE, FALSE, 8);
1582   gtk_widget_show (pixmap);
1583
1584
1585   button = gtk_hseparator_new ();
1586   gtk_box_pack_start (GTK_BOX(vbox), button, FALSE, FALSE, 8);
1587   gtk_widget_show (button);
1588
1589   label = gtk_label_new (_("This user interface by Conrad Parker,\n"
1590                            "Copyright (C) 2002 CSIRO Australia.\n\n"));
1591   gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
1592   gtk_widget_show (label);
1593
1594   /* OK */
1595
1596   ok_button = gtk_button_new_with_label (_("Save"));
1597   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (ok_button), GTK_CAN_DEFAULT);
1598   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), ok_button,
1599                       TRUE, TRUE, 0);
1600   gtk_widget_show (ok_button);
1601   g_signal_connect (G_OBJECT(ok_button), "clicked",
1602                       G_CALLBACK (vorbis_save_options_dialog_ok_cb),
1603                       sample);
1604
1605   /* Cancel */
1606
1607   button = gtk_button_new_with_label (_("Don't save"));
1608   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (button), GTK_CAN_DEFAULT);
1609   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), button,
1610                       TRUE, TRUE, 0);
1611   gtk_widget_show (button);
1612   g_signal_connect (G_OBJECT(button), "clicked",
1613                       G_CALLBACK (vorbis_save_options_dialog_cancel_cb),
1614                       sample);
1615
1616   gtk_widget_grab_default (ok_button);
1617
1618   return (dialog);
1619 }
1620
1621 int
1622 vorbis_save_options_dialog (sw_sample * sample, char * pathname)
1623 {
1624   GtkWidget * dialog;
1625
1626   dialog = create_vorbis_encoding_options_dialog (sample, pathname);
1627   gtk_widget_show (dialog);
1628
1629   return 0;
1630 }
1631
1632 #endif /* HAVE_OGGVORBIS */
Note: See TracBrowser for help on using the browser.