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 "speexdec.c" and "speexenc.c" in the Speex coded
24 * source code, Copyright (C) 2002 Jean-Marc Valin
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 *
30 * - Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 *
33 * - Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 *
37 * - Neither the name of the Xiph.org Foundation nor the names of its
38 * contributors may be used to endorse or promote products derived from
39 * this software without specific prior written permission.
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
42 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
43 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
44 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
45 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
46 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
47 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
48 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
49 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
50 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
51 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 */
53
54 #ifdef HAVE_CONFIG_H
55 # include <config.h>
56 #endif
57
58 #ifdef HAVE_SPEEX
59
60 #include <stdlib.h>
61 #include <stdio.h>
62 #include <string.h>
63 #include <sys/types.h>
64 #include <sys/stat.h>
65 #include <fcntl.h>
66 #include <unistd.h>
67 #include <math.h>
68 #include <pthread.h>
69 #include <errno.h>
70 #include <ctype.h>
71
72 #include <ogg/ogg.h>
73 #ifdef HAVE_SPEEX_SUBDIR
74 #include <speex/speex.h>
75 #include <speex/speex_header.h>
76 #include <speex/speex_stereo.h>
77 #include <speex/speex_callbacks.h>
78 #else
79 #include <speex.h>
80 #include <speex_header.h>
81 #include <speex_stereo.h>
82 #include <speex_callbacks.h>
83 #endif
84
85 #define BUFFER_LEN 1024
86
87 #include <glib.h>
88 #include <gdk/gdkkeysyms.h>
89 #include <gtk/gtk.h>
90
91 #include <sweep/sweep_i18n.h>
92 #include <sweep/sweep_types.h>
93 #include <sweep/sweep_typeconvert.h>
94 #include <sweep/sweep_sample.h>
95 #include <sweep/sweep_undo.h>
96 #include <sweep/sweep_sounddata.h>
97
98 #include "sample.h"
99 #include "interface.h"
100 #include "file_dialogs.h"
101 #include "file_sndfile.h"
102 #include "question_dialogs.h"
103 #include "preferences.h"
104 #include "print.h"
105 #include "view.h"
106
107 #include "../pixmaps/xifish.xpm"
108 #include "../pixmaps/speex_logo.xpm"
109
110 /* MAINTENANCE:
111 *
112 * Upon release of Speex 1.0, force a requirement on that version in
113 * configure. Then, remove all references to SPEEX_HAVE_BETA4 (assume
114 * this is true, as those features will be available), and also assume
115 * that SPEEX_NB_MODES > 2. This should reduce the random ifdef'ing
116 * present to accomodate the flux of prerelease versions of Speex.
117 */
118
119 #ifdef SPEEX_SET_DTX
120 #define HAVE_SPEEX_BETA4
121 #endif
122
123 #define BUF_LEN 128
124
125 #define MODE_KEY "Speex_Mode"
126 #define FEATURES_KEY "Speex_Features"
127 #define QUALITY_KEY "Speex_Quality"
128 #define BR_KEY "Speex_BR"
129 #define BITRATE_KEY "Speex_Bitrate"
130 #define COMPLEXITY_KEY "Speex_Complexity"
131 #define SERIALNO_KEY "OggSpeex_Serialno"
132 #define FRAMEPACK_KEY "OggSpeex_FramePack"
133
134 /* Mode choices */
135 #define MODE_NARROWBAND 0
136 #define MODE_WIDEBAND 1
137 #define MODE_ULTRAWIDEBAND 2
138
139 /* Feature flags */
140 #define FEAT_VBR 1
141 #define FEAT_VAD 2
142 #define FEAT_DTX 4
143
144 #ifdef HAVE_SPEEX_BETA4
145 #define DEFAULT_FEATURES (FEAT_VBR | FEAT_VAD | FEAT_DTX)
146 #else
147 #define DEFAULT_FEATURES (FEAT_VBR)
148 #endif
149
150 #define DEFAULT_QUALITY 8.0
151 #define DEFAULT_COMPLEXITY 3.0
152 #define DEFAULT_FRAMEPACK 1
153
154 #define DEFAULT_ENH_ENABLED 1
155
156 extern GtkStyle * style_bw;
157
158 #define READ_SIZE 200
159
160 /*
161 * file_is_ogg_speex (pathname)
162 *
163 * This function attempts to determine if a given file is an ogg speex file
164 * by attempting to parse enough of the stream to decode an initial speex
165 * header. If any steps along the way fail, it returns false;
166 */
167 static gboolean
file_is_ogg_speex(const char * pathname)168 file_is_ogg_speex (const char * pathname)
169 {
170 int fd;
171 ssize_t nread;
172
173 ogg_sync_state oy;
174 ogg_page og;
175 ogg_packet op;
176 ogg_stream_state os;
177
178 char * ogg_data;
179
180 const SpeexMode *mode;
181 SpeexHeader *header;
182
183 fd = open (pathname, O_RDONLY);
184 if (fd == -1) {
185 return FALSE;
186 }
187
188 ogg_sync_init (&oy);
189 ogg_data = ogg_sync_buffer (&oy, READ_SIZE);
190 if (ogg_data == NULL) goto out_false_sync;
191 if ((nread = read (fd, ogg_data, READ_SIZE)) <= 0) goto out_false_sync;
192 ogg_sync_wrote (&oy, nread);
193 if (ogg_sync_pageout (&oy, &og) != 1) goto out_false_sync;
194 ogg_stream_init (&os, ogg_page_serialno (&og));
195 ogg_stream_pagein (&os, &og);
196 if (ogg_stream_packetout (&os, &op) != 1) goto out_false_stream;
197 header = speex_packet_to_header (op.packet, op.bytes);
198 if (!header) goto out_false_stream;
199 if (header->mode >= SPEEX_NB_MODES) goto out_false_stream;
200 mode = speex_mode_list[header->mode];
201 if (mode->bitstream_version != header->mode_bitstream_version)
202 goto out_false_stream;
203
204 ogg_sync_clear (&oy);
205 ogg_stream_clear (&os);
206
207 close (fd);
208
209 return TRUE;
210
211 out_false_stream:
212 ogg_stream_clear (&os);
213
214 out_false_sync:
215 ogg_sync_clear (&oy);
216
217 close (fd);
218
219 return FALSE;
220 }
221
222 static void *
process_header(ogg_packet * op,int enh_enabled,int * frame_size,int * rate,int * nframes,int forceMode,int * channels,SpeexStereoState * stereo,int * extra_headers)223 process_header(ogg_packet *op, int enh_enabled, int * frame_size, int * rate,
224 int * nframes, int forceMode, int * channels,
225 SpeexStereoState * stereo, int * extra_headers)
226 {
227 void *st;
228 SpeexMode *mode;
229 SpeexHeader *header;
230 int modeID;
231 SpeexCallback callback;
232
233 header = speex_packet_to_header((char*)op->packet, op->bytes);
234 if (!header) {
235 info_dialog_new ("Speex error", NULL, "Speex: cannot read header");
236 return NULL;
237 }
238 if (header->mode >= SPEEX_NB_MODES || header->mode < 0) {
239 info_dialog_new ("Speex error", NULL,
240 "Mode number %d does not (any longer) exist in this version\n",
241 header->mode);
242 return NULL;
243 }
244
245 modeID = header->mode;
246 if (forceMode!=-1)
247 modeID = forceMode;
248 mode = (SpeexMode *)speex_mode_list[modeID];
249
250 #ifdef HAVE_SPEEX_BETA4
251 if (header->speex_version_id > 1) {
252 info_dialog_new ("Speex error", NULL,
253 "This file was encoded with Speex bit-stream version %d, "
254 "which I don't know how to decode\n",
255 header->speex_version_id);
256 return NULL;
257 }
258 #endif
259
260 if (mode->bitstream_version < header->mode_bitstream_version) {
261 info_dialog_new ("Speex error", NULL,
262 "The file was encoded with a newer version of Speex. "
263 "You need to upgrade in order to play it.\n");
264 return NULL;
265 }
266
267 if (mode->bitstream_version > header->mode_bitstream_version) {
268 info_dialog_new ("Speex error", NULL,
269 "The file was encoded with an older version of Speex. "
270 "You would need to downgrade the version in order to play it.\n");
271 return NULL;
272 }
273
274 st = speex_decoder_init(mode);
275 if (!st) {
276 info_dialog_new ("Speex error", NULL,
277 "Decoder initialization failed.\n");
278 return NULL;
279 }
280
281 speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
282 speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
283
284 if (!(*channels==1))
285 {
286 callback.callback_id = SPEEX_INBAND_STEREO;
287 callback.func = speex_std_stereo_request_handler;
288 callback.data = stereo;
289 speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
290 }
291 if (*rate==-1)
292 *rate = header->rate;
293 /* Adjust rate if --force-* options are used */
294 if (forceMode!=-1)
295 {
296 if (header->mode < forceMode)
297 *rate <<= (forceMode - header->mode);
298 if (header->mode > forceMode)
299 *rate >>= (header->mode - forceMode);
300 }
301
302 speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
303
304 *nframes = header->frames_per_packet;
305
306 if (*channels == -1)
307 *channels = header->nb_channels;
308
309 #ifdef DEBUG
310 fprintf (stderr, "Decoding %d Hz audio using %s mode",
311 *rate, mode->modeName);
312
313 if (*channels==1)
314 fprintf (stderr, " (mono");
315 else
316 fprintf (stderr, " (stereo");
317
318 if (header->vbr)
319 fprintf (stderr, " (VBR)\n");
320 else
321 fprintf(stderr, "\n");
322 #endif
323
324 #ifdef HAVE_SPEEX_BETA4
325 *extra_headers = header->extra_headers;
326 #else
327 *extra_headers = 0;
328 #endif
329
330 free(header);
331
332 return st;
333 }
334
335 static sw_sample *
sample_load_speex_data(sw_op_instance * inst)336 sample_load_speex_data (sw_op_instance * inst)
337 {
338 sw_sample * sample = inst->sample;
339
340 int fd;
341 struct stat statbuf;
342
343 void * st = NULL;
344 SpeexBits bits;
345 int frame_size = 0;
346 int rate = -1;
347 int channels = -1;
348 int extra_headers;
349 SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
350 int packet_count = 0;
351 int stream_init = 0;
352
353 ogg_sync_state oy;
354 ogg_page og;
355 ogg_packet op;
356 ogg_stream_state os;
357
358 char * ogg_data;
359
360 int enh_enabled = DEFAULT_ENH_ENABLED;
361 int nframes = 2;
362 int eos = 0;
363 int forceMode = -1;
364
365 int i, j;
366 sw_audio_t * d = NULL;
367 sw_framecount_t frames_total = 0, frames_decoded = 0;
368 size_t file_length, remaining, n;
369 ssize_t nread;
370 gint percent;
371
372 gboolean active = TRUE;
373
374 fd = open (sample->pathname, O_RDONLY);
375 if (fd == -1) {
376 sweep_perror (errno, "failed open in sample_load_speex_data");
377 return NULL;
378 }
379
380 if (fstat (fd, &statbuf) == -1) {
381 sweep_perror (errno, "failed stat in sample_load_speex_data");
382 return NULL;
383 }
384
385 file_length = remaining = statbuf.st_size;
386
387 /* Init Ogg sync */
388 ogg_sync_init (&oy);
389
390 speex_bits_init (&bits);
391
392 while (active && remaining > 0) {
393 g_mutex_lock (sample->ops_mutex);
394
395 if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
396 active = FALSE;
397 } else {
398 n = MIN (remaining, READ_SIZE);
399
400 ogg_data = ogg_sync_buffer (&oy, n);
401 nread = read (fd, ogg_data, n);
402 if (nread == -1) {
403 sweep_perror (errno, "speex: %s", sample->pathname);
404 active = FALSE;
405 } else if (nread == 0) {
406 /* eof */
407 active = FALSE;
408 } else {
409 ogg_sync_wrote (&oy, nread);
410 n = (size_t)nread;
411 }
412
413 /* Loop for all complete pages we got */
414 while (active && ogg_sync_pageout (&oy, &og) == 1) {
415 if (stream_init == 0) {
416 ogg_stream_init (&os, ogg_page_serialno (&og));
417 stream_init = 1;
418 }
419
420 /* Add page to the bitstream */
421 ogg_stream_pagein (&os, &og);
422
423 /* Extract all available packets */
424 while (!eos && ogg_stream_packetout (&os, &op) == 1) {
425 if (packet_count == 0) {/* header */
426 st = process_header (&op, enh_enabled, &frame_size, &rate,
427 &nframes, forceMode, &channels, &stereo,
428 &extra_headers);
429 if (st == NULL) {
430 /*printf ("Not Speex!\n");*/
431 active = FALSE;
432 }
433
434 sample->sounddata->format->rate = rate;
435 sample->sounddata->format->channels = channels;
436
437 if (nframes == 0)
438 nframes = 1;
439
440 } else if (packet_count <= 1+extra_headers) {
441 /* XXX: metadata, extra_headers: ignore */
442 } else {
443 if (op.e_o_s)
444 eos = 1;
445
446 /* Copy Ogg packet to Speex bitstream */
447 speex_bits_read_from (&bits, (char *)op.packet, op.bytes);
448
449 frames_total += nframes * frame_size;
450
451 if (sample->sounddata->nr_frames != frames_total) {
452 sample->sounddata->data =
453 g_realloc (sample->sounddata->data,
454 frames_total * channels * sizeof (sw_audio_t));
455 }
456
457 sample->sounddata->nr_frames = frames_total;
458
459 d = &((sw_audio_t *)sample->sounddata->data)
460 [frames_decoded * channels];
461
462 if (d != NULL) {
463 for (j = 0; j < nframes; j++) {
464 /* Decode frame */
465 speex_decode (st, &bits, d);
466 #ifdef DEBUG
467 if (speex_bits_remaining (&bits) < 0) {
468 info_dialog_new ("Speex warning", NULL,
469 "Speex: decoding overflow -- corrupted stream at frame %ld", frames_decoded + (j * frame_size));
470 }
471 #endif
472 if (channels == 2)
473 speex_decode_stereo (d, frame_size, &stereo);
474
475 for (i = 0; i < frame_size * channels; i++) {
476 d[i] /= 32767.0;
477 }
478 d += (frame_size * channels);
479 frames_decoded += frame_size;
480 }
481 }
482 }
483
484 packet_count ++;
485 }
486
487 remaining -= n;
488
489 percent = (file_length - remaining) * 100 / file_length;
490 sample_set_progress_percent (sample, percent);
491 }
492 }
493
494 g_mutex_unlock (sample->ops_mutex);
495 }
496
497 if (st) speex_decoder_destroy (st);
498 speex_bits_destroy (&bits);
499 ogg_sync_clear (&oy);
500 ogg_stream_clear (&os);
501
502 close (fd);
503
504 if (remaining <= 0) {
505 stat (sample->pathname, &statbuf);
506 sample->last_mtime = statbuf.st_mtime;
507 sample->edit_ignore_mtime = FALSE;
508 sample->modified = FALSE;
509 }
510
511 sample_set_edit_state (sample, SWEEP_EDIT_STATE_DONE);
512
513 return sample;
514 }
515
516 static sw_operation speex_load_op = {
517 SWEEP_EDIT_MODE_FILTER,
518 (SweepCallback)sample_load_speex_data,
519 (SweepFunction)NULL,
520 (SweepCallback)NULL, /* undo */
521 (SweepFunction)NULL,
522 (SweepCallback)NULL, /* redo */
523 (SweepFunction)NULL
524 };
525
526 static sw_sample *
sample_load_speex_info(sw_sample * sample,char * pathname)527 sample_load_speex_info (sw_sample * sample, char * pathname)
528 {
529 #undef BUF_LEN
530 #define BUF_LEN 128
531 char buf[BUF_LEN];
532
533 gboolean isnew = (sample == NULL);
534
535 sw_view * v;
536
537 if (!file_is_ogg_speex (pathname)) return NULL;
538
539 /* Create the sample/sounddata, initially with length 0, to be grown
540 * as the file is decoded
541 */
542 if (sample == NULL) {
543 /* Channels and rate will be set during decoding and are basically
544 * irrelevent here. Set them to 1, 8000 assuming these are the most
545 * likely values, in which case the file info displayed in the window
546 * will not change suddenly
547 */
548 sample = sample_new_empty(pathname, 1, 8000, 0);
549 } else {
550 int channels, rate;
551
552 /* Set the channels and rate of the recreated sounddata to be the same
553 * as the old one, as they are most likely the same after a reload */
554 channels = sample->sounddata->format->channels;
555 rate = sample->sounddata->format->rate;
556
557 sounddata_destroy (sample->sounddata);
558 sample->sounddata = sounddata_new_empty (channels, rate, 0);
559 }
560
561 if(!sample) {
562 return NULL;
563 }
564
565 sample->file_method = SWEEP_FILE_METHOD_SPEEX;
566 sample->file_info = NULL;
567
568 sample_bank_add(sample);
569
570 if (isnew) {
571 v = view_new_all (sample, 1.0);
572 sample_add_view (sample, v);
573 } else {
574 trim_registered_ops (sample, 0);
575 }
576
577 g_snprintf (buf, BUF_LEN, _("Loading %s"), g_basename (sample->pathname));
578
579 schedule_operation (sample, buf, &speex_load_op, sample);
580
581 return sample;
582 }
583
584 sw_sample *
speex_sample_reload(sw_sample * sample)585 speex_sample_reload (sw_sample * sample)
586 {
587 if (sample == NULL) return NULL;
588
589 return sample_load_speex_info (sample, sample->pathname);
590 }
591
592 sw_sample *
speex_sample_load(char * pathname)593 speex_sample_load (char * pathname)
594 {
595 if (pathname == NULL) return NULL;
596
597 return sample_load_speex_info (NULL, pathname);
598 }
599
600
601 /*
602 * comment creation: from speexenc.c
603 */
604
605 /*
606 Comments will be stored in the Vorbis style.
607 It is describled in the "Structure" section of
608 http://www.xiph.org/ogg/vorbis/doc/v-comment.html
609
610 The comment header is decoded as follows:
611 1) [vendor_length] = read an unsigned integer of 32 bits
612 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
613 3) [user_comment_list_length] = read an unsigned integer of 32 bits
614 4) iterate [user_comment_list_length] times {
615 5) [length] = read an unsigned integer of 32 bits
616 6) this iteration's user comment = read a UTF-8 vector as [length] octets
617 }
618 7) [framing_bit] = read a single bit as boolean
619 8) if ( [framing_bit] unset or end of packet ) then ERROR
620 9) done.
621
622 If you have troubles, please write to ymnk@jcraft.com.
623 */
624
625 #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
626 ((buf[base+2]<<16)&0xff0000)| \
627 ((buf[base+1]<<8)&0xff00)| \
628 (buf[base]&0xff))
629 #define writeint(buf, base, val) do{ buf[base+3]=(val>>24)&0xff; \
630 buf[base+2]=(val>>16)&0xff; \
631 buf[base+1]=(val>>8)&0xff; \
632 buf[base]=(val)&0xff; \
633 }while(0)
634
comment_init(char ** comments,int * length,char * vendor_string)635 void comment_init(char **comments, int* length, char *vendor_string)
636 {
637 int vendor_length=strlen(vendor_string);
638 int user_comment_list_length=0;
639 int len=4+vendor_length+4;
640 char *p=(char*)malloc(len);
641 if(p==NULL){
642 }
643 writeint(p, 0, vendor_length);
644 memcpy(p+4, vendor_string, vendor_length);
645 writeint(p, 4+vendor_length, user_comment_list_length);
646 *length=len;
647 *comments=p;
648 }
comment_add(char ** comments,int * length,char * tag,char * val)649 void comment_add(char **comments, int* length, char *tag, char *val)
650 {
651 char* p=*comments;
652 int vendor_length=readint(p, 0);
653 int user_comment_list_length=readint(p, 4+vendor_length);
654 int tag_len=(tag?strlen(tag):0);
655 int val_len=strlen(val);
656 int len=(*length)+4+tag_len+val_len;
657
658 p=realloc(p, len);
659 if(p==NULL){
660 }
661
662 writeint(p, *length, (tag_len+val_len)); /* length of comment */
663 if(tag) memcpy(p+*length+4, tag, tag_len); /* comment */
664 memcpy(p+*length+4+tag_len, val, val_len); /* comment */
665 writeint(p, 4+vendor_length, (user_comment_list_length+1));
666
667 *comments=p;
668 *length=len;
669 }
670 #undef readint
671 #undef writeint
672
673
674 typedef struct {
675 gchar * pathname;
676 gint mode;
677 gint features;
678 gboolean use_br;
679 gfloat quality; /* either way */
680 gint bitrate;
681 gint complexity;
682 gint framepack;
683 long serialno;
684 } speex_save_options;
685
686 #define MAX_FRAME_SIZE 2000
687 #define MAX_FRAME_BYTES 2000
688
689 static int
speex_sample_save_thread(sw_op_instance * inst)690 speex_sample_save_thread (sw_op_instance * inst)
691 {
692 sw_sample * sample = inst->sample;
693 gchar * pathname = (gchar *)inst->do_data;
694
695 FILE * outfile;
696 sw_format * format;
697 sw_audio_t * d;
698 sw_framecount_t remaining, len, run_total;
699 sw_framecount_t nr_frames, cframes;
700 gint percent = 0;
701
702 speex_save_options * so;
703
704 ogg_stream_state os; /* take physical pages, weld into a logical
705 stream of packets */
706 ogg_page og; /* one Ogg bitstream page. Speex packets are inside */
707 ogg_packet op; /* one raw packet of data for decode */
708
709 float input[MAX_FRAME_SIZE];
710 gchar cbits[MAX_FRAME_BYTES];
711 int nbBytes;
712 int id = 0;
713
714 int frame_size;
715 SpeexMode * mode = NULL;
716 SpeexHeader header;
717 void * st;
718 SpeexBits bits;
719
720 gchar * vendor_string = "Encoded with Sweep " VERSION " (metadecks.org)";
721 gchar * comments = NULL;
722 int comments_length = 0;
723
724 int eos = 0;
725 int i, j;
726
727 gboolean active = TRUE;
728
729 size_t n, bytes_written = 0;
730 double average_bitrate = 0.0;
731
732 struct stat statbuf;
733 int errno_save = 0;
734
735 if (sample == NULL) return -1;
736
737 so = (speex_save_options *)sample->file_info;
738
739 format = sample->sounddata->format;
740
741 nr_frames = sample->sounddata->nr_frames;
742 cframes = nr_frames / 100;
743 if (cframes == 0) cframes = 1;
744
745 remaining = nr_frames;
746 run_total = 0;
747
748 #if 0
749 if (format->channels != 1) {
750 fprintf (stderr, "Unsupported channel count for Speex encoding\n");
751 return -1;
752 }
753 #endif
754
755 if (!(outfile = fopen (pathname, "w"))) {
756 sweep_perror (errno, pathname);
757 return -1;
758 }
759
760 switch (so->mode) {
761 case MODE_NARROWBAND:
762 mode = (SpeexMode *) &speex_nb_mode;
763 break;
764 case MODE_WIDEBAND:
765 mode = (SpeexMode *) &speex_wb_mode;
766 break;
767 #if (SPEEX_NB_MODES > 2)
768 case MODE_ULTRAWIDEBAND:
769 mode = (SpeexMode *) &speex_uwb_mode;
770 break;
771 #endif
772 default:
773 mode = (SpeexMode *) &speex_nb_mode;
774 break;
775 }
776
777 speex_init_header (&header, format->rate, 1 , mode);
778 header.frames_per_packet = so->framepack;
779 header.vbr = (so->features & FEAT_VBR) ? 1 : 0;
780 header.nb_channels = format->channels;
781
782 #ifdef DEBUG
783 fprintf (stderr, "Encoding %d Hz audio using %s mode\n",
784 header.rate, mode->modeName);
785 #endif
786
787 /* initialise Speex encoder */
788 st = speex_encoder_init (mode);
789
790 /* initialise comments */
791 comment_init (&comments, &comments_length, vendor_string);
792
793 /* set up our packet->stream encoder */
794 ogg_stream_init (&os, so->serialno);
795
796 /* write header */
797
798 {
799 int bytes = op.bytes;
800 op.packet = (unsigned char *)
801 speex_header_to_packet (&header, &bytes);
802 op.bytes = bytes;
803 op.b_o_s = 1;
804 op.e_o_s = 0;
805 op.granulepos = 0;
806 op.packetno = 0;
807 ogg_stream_packetin(&os, &op);
808 free(op.packet);
809
810 op.packet = (unsigned char *)comments;
811 op.bytes = comments_length;
812 op.b_o_s = 0;
813 op.e_o_s = 0;
814 op.granulepos = 0;
815 op.packetno = 1;
816 ogg_stream_packetin(&os, &op);
817
818 /* This ensures the actual
819 * audio data will start on a new page, as per spec
820 */
821 while(!eos){
822 int result = ogg_stream_flush (&os, &og);
823 if (result == 0) break;
824
825 n = fwrite (og.header, 1, og.header_len, outfile);
826 n += fwrite (og.body, 1, og.body_len, outfile);
827
828 if (fflush (outfile) == 0) {
829 bytes_written += n;
830 } else {
831 errno_save = errno;
832 eos = 1; /* pffft -- this encoding wasn't going anywhere */
833 }
834 }
835 }
836
837 if (comments) g_free (comments);
838
839 speex_encoder_ctl (st, SPEEX_SET_SAMPLING_RATE, &format->rate);
840
841 speex_encoder_ctl (st, SPEEX_GET_FRAME_SIZE, &frame_size);
842 speex_encoder_ctl (st, SPEEX_SET_COMPLEXITY, &so->complexity);
843 if (so->features & FEAT_VBR) {
844 int tmp = 1;
845 speex_encoder_ctl (st, SPEEX_SET_VBR, &tmp);
846 speex_encoder_ctl (st, SPEEX_SET_VBR_QUALITY, &so->quality);
847 #ifdef HAVE_SPEEX_BETA4
848 if (so->use_br) {
849 speex_encoder_ctl (st, SPEEX_SET_ABR, &so->bitrate);
850 }
851 #endif
852 } else {
853 int tmp = (int)floor(so->quality);
854 speex_encoder_ctl (st, SPEEX_SET_QUALITY, &tmp);
855 if (so->use_br) {
856 speex_encoder_ctl (st, SPEEX_SET_BITRATE, &so->bitrate);
857 }
858 }
859
860 #ifdef HAVE_SPEEX_BETA4
861 if (so->features & FEAT_VAD) {
862 int tmp = 1;
863 speex_encoder_ctl (st, SPEEX_SET_VAD, &tmp);
864 if (so->features & FEAT_DTX) {
865 speex_encoder_ctl (st, SPEEX_SET_DTX, &tmp);
866 }
867 }
868 #endif
869
870 speex_bits_init (&bits);
871
872 while (!eos) {
873 g_mutex_lock (sample->ops_mutex);
874
875 if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
876 active = FALSE;
877 }
878
879 if (active == FALSE || remaining <= 0) {
880 /* Mark the end of stream */
881 /* XXX: this will be set when this packet is paged out: eos = 1; */
882 op.e_o_s = 1;
883 } else {
884 op.e_o_s = 0;
885
886 /* data to encode */
887
888 for (i = 0; i < so->framepack; i++) {
889 if (remaining > 0) {
890 len = MIN (remaining, frame_size);
891
892 d = &((sw_audio_t *)sample->sounddata->data)
893 [run_total * format->channels];
894
895 memcpy (input, d, sizeof (sw_audio_t) * len * format->channels);
896
897 /* rip channel 0 out, in required format */
898 for (j = 0; j < len * format->channels; j++) {
899 input[j] *= 32767.0;
900 }
901
902 if (format->channels == 2)
903 speex_encode_stereo (input, len, &bits);
904 speex_encode (st, input, &bits);
905
906 remaining -= len;
907
908 run_total += len;
909 percent = run_total / cframes;
910 sample_set_progress_percent (sample, percent);
911 } else {
912 /*speex_bits_pack (&bits, 0, 7);*/
913 speex_bits_pack (&bits, 15, 5);
914 }
915
916 id++;
917 }
918 }
919
920 g_mutex_unlock (sample->ops_mutex);
921
922 nbBytes = speex_bits_write (&bits, cbits, MAX_FRAME_BYTES);
923 speex_bits_reset (&bits);
924
925 /* Put it in an ogg packet */
926 op.packet = (unsigned char *)cbits;
927 op.bytes = nbBytes;
928 op.b_o_s = 0;
929 /* op.e_o_s was set above */
930 #if 0 /* XXX: was set above */
931 if (eos)
932 op.e_o_s = 1;
933 else
934 op.e_o_s = 0;
935 #endif
936 op.granulepos = id * frame_size;
937 op.packetno = 2 + (id-1)/so->framepack;
938
939 /* weld the packet into the bitstream */
940 ogg_stream_packetin(&os,&op);
941
942 /* write out pages (if any) */
943 while(!eos){
944 int result=ogg_stream_pageout(&os,&og);
945 if(result==0)break;
946
947 n = fwrite (og.header, 1, og.header_len, outfile);
948 n += fwrite (og.body, 1, og.body_len, outfile);
949
950 if (fflush (outfile) == 0) {
951 bytes_written += n;
952 } else {
953 errno_save = errno;
954 active = FALSE;
955 }
956
957 /* this could be set above, but for illustrative purposes, I do
958 it here (to show that we know where the stream ends) */
959 if (ogg_page_eos(&og)) eos=1;
960 }
961 }
962
963 #if 0
964 /*Flush all pages left to be written*/
965 while (ogg_stream_flush(&os, &og))
966 {
967 n = fwrite (og.header, 1, og.header_len, outfile);
968 n += fwrite (og.body, 1, og.body_len, outfile);
969
970 if (fflush (outfile) == 0) {
971 bytes_written += n;
972 } else {
973 errno_save = errno;
974 active = FALSE;
975 }
976 }
977 #endif
978
979 /* clean up and exit. speex_info_clear() must be called last */
980
981 speex_encoder_destroy (st);
982 speex_bits_destroy (&bits);
983 ogg_stream_clear(&os);
984
985 fclose (outfile);
986
987 /* Report success or failure; Calculate and display statistics */
988
989 #undef BUF_LEN
990 #define BUF_LEN 16
991
992 if (remaining <= 0) {
993 char time_buf[BUF_LEN], bytes_buf[BUF_LEN];
994
995 #if 1
996 sample_store_and_free_pathname (sample, pathname);
997 #else
998 g_free (pathname);
999 #endif
1000
1001 /* Mark the last mtime for this sample */
1002
1003 stat (sample->pathname, &statbuf);
1004 sample->last_mtime = statbuf.st_mtime;
1005 sample->edit_ignore_mtime = FALSE;
1006 sample->modified = FALSE;
1007
1008 snprint_time (time_buf, BUF_LEN,
1009 frames_to_time (format, nr_frames - remaining));
1010
1011 snprint_bytes (bytes_buf, BUF_LEN, bytes_written);
1012
1013 average_bitrate =
1014 8.0/1000.0*((double)bytes_written/((double)nr_frames/(double)format->rate));
1015
1016 info_dialog_new (_("Speex encoding results"), xifish_xpm,
1017 "Encoding of %s succeeded.\n\n"
1018 "%s written, %s audio\n"
1019 "Average bitrate: %.1f kbps",
1020 g_basename (sample->pathname),
1021 bytes_buf, time_buf,
1022 average_bitrate);
1023 } else {
1024 char time_buf[BUF_LEN], bytes_buf[BUF_LEN];
1025
1026 snprint_time (time_buf, BUF_LEN,
1027 frames_to_time (format, nr_frames - remaining));
1028
1029 snprint_bytes (bytes_buf, BUF_LEN, bytes_written);
1030
1031 average_bitrate =
1032 8.0/1000.0*((double)bytes_written/((double)(nr_frames - remaining)/(double)format->rate));
1033 if (isnan(average_bitrate)) average_bitrate = 0.0;
1034
1035 if (errno_save == 0) {
1036 info_dialog_new (_("Speex encoding results"), xifish_xpm,
1037 "Encoding of %s FAILED\n\n"
1038 "%s written, %s audio (%d%% complete)\n"
1039 "Average bitrate: %.1f kbps",
1040 g_basename (pathname), bytes_buf, time_buf, percent,
1041 average_bitrate);
1042 } else {
1043 sweep_perror (errno_save,
1044 "Encoding of %s FAILED\n\n"
1045 "%s written, %s audio (%d%% complete)\n"
1046 "Average bitrate: %.1f kbps",
1047 g_basename (pathname), bytes_buf, time_buf, percent,
1048 average_bitrate);
1049 }
1050 }
1051
1052 sample_set_edit_state (sample, SWEEP_EDIT_STATE_DONE);
1053
1054 return 0;
1055 }
1056
1057 static sw_operation speex_save_op = {
1058 SWEEP_EDIT_MODE_META,
1059 (SweepCallback)speex_sample_save_thread,
1060 (SweepFunction)NULL,
1061 (SweepCallback)NULL, /* undo */
1062 (SweepFunction)NULL,
1063 (SweepCallback)NULL, /* redo */
1064 (SweepFunction)NULL
1065 };
1066
1067 int
speex_sample_save(sw_sample * sample,char * pathname)1068 speex_sample_save (sw_sample * sample, char * pathname)
1069 {
1070 #undef BUF_LEN
1071 #define BUF_LEN 64
1072 char buf[BUF_LEN];
1073
1074 g_snprintf (buf, BUF_LEN, _("Saving %s"), g_basename (pathname));
1075
1076 schedule_operation (sample, buf, &speex_save_op, pathname);
1077
1078 return 0;
1079 }
1080
1081 static void
speex_save_options_dialog_ok_cb(GtkWidget * widget,gpointer data)1082 speex_save_options_dialog_ok_cb (GtkWidget * widget, gpointer data)
1083 {
1084 sw_sample * sample = (sw_sample *)data;
1085 GtkWidget * dialog;
1086 speex_save_options * so;
1087 GtkWidget * checkbutton;
1088 GtkWidget * entry;
1089 const gchar * text;
1090
1091 gboolean use_br;
1092 GtkObject * adj;
1093 int mode, features, quality, bitrate, complexity, framepack;
1094 gboolean rem_encode;
1095 long serialno;
1096 gboolean rem_serialno;
1097
1098 char * pathname;
1099
1100 so = g_malloc (sizeof(speex_save_options));
1101
1102 dialog = gtk_widget_get_toplevel (widget);
1103
1104 /* Mode */
1105
1106 mode =
1107 GPOINTER_TO_INT(g_object_get_data (G_OBJECT(dialog), "mode_choice"));
1108
1109 /* Features */
1110
1111 features =
1112 GPOINTER_TO_INT(g_object_get_data (G_OBJECT(dialog),
1113 "features_choice"));
1114
1115 adj = GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "quality_adj"));
1116 quality = (int)GTK_ADJUSTMENT(adj)->value;
1117
1118 adj = GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "complexity_adj"));
1119 complexity = (int)GTK_ADJUSTMENT(adj)->value;
1120
1121 adj = GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "framepack_adj"));
1122 framepack = (int)GTK_ADJUSTMENT(adj)->value;
1123
1124 checkbutton =
1125 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "br_chb"));
1126 use_br = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(checkbutton));
1127
1128 entry =
1129 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "br_entry"));
1130 text = gtk_entry_get_text (GTK_ENTRY(entry));
1131 bitrate = (int)strtol (text, (char **)NULL, 0);
1132
1133 /* rem encode */
1134 checkbutton =
1135 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "rem_encode_chb"));
1136 rem_encode =
1137 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(checkbutton));
1138
1139 entry =
1140 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "serialno_entry"));
1141 text = gtk_entry_get_text (GTK_ENTRY(entry));
1142 serialno = strtol (text, (char **)NULL, 0);
1143 if (serialno == LONG_MIN || serialno == LONG_MAX) serialno = random ();
1144
1145 checkbutton =
1146 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "rem_serialno_chb"));
1147 rem_serialno =
1148 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(checkbutton));
1149
1150 pathname = g_object_get_data (G_OBJECT(dialog), "pathname");
1151
1152 gtk_widget_destroy (dialog);
1153
1154 if (rem_encode) {
1155 prefs_set_int (MODE_KEY, mode);
1156 prefs_set_int (FEATURES_KEY, features);
1157 prefs_set_int (BR_KEY, use_br);
1158 prefs_set_int (QUALITY_KEY, quality);
1159 prefs_set_int (BITRATE_KEY, bitrate);
1160 prefs_set_int (COMPLEXITY_KEY, complexity);
1161 prefs_set_int (FRAMEPACK_KEY, framepack);
1162 }
1163
1164 if (rem_serialno) {
1165 prefs_set_long (SERIALNO_KEY, serialno);
1166 } else {
1167 prefs_delete (SERIALNO_KEY);
1168 }
1169
1170 if (sample->file_info) {
1171 g_free (sample->file_info);
1172 }
1173
1174 so->mode = mode;
1175 so->features = features;
1176 so->use_br = use_br;
1177 so->quality = quality;
1178 so->bitrate = bitrate;
1179 so->complexity = complexity;
1180 so->framepack = framepack;
1181
1182 so->serialno = serialno;
1183
1184 sample->file_info = so;
1185
1186 speex_sample_save (sample, pathname);
1187 }
1188
1189 static void
speex_save_options_dialog_cancel_cb(GtkWidget * widget,gpointer data)1190 speex_save_options_dialog_cancel_cb (GtkWidget * widget, gpointer data)
1191 {
1192 GtkWidget * dialog;
1193
1194 dialog = gtk_widget_get_toplevel (widget);
1195 gtk_widget_destroy (dialog);
1196
1197 /* if the sample bank is empty, quit the program */
1198 sample_bank_remove (NULL);
1199 }
1200
1201 typedef struct {
1202 int number;
1203 char * name;
1204 char * desc;
1205 } sw_choice;
1206
1207 static sw_choice mode_choices[] = {
1208 { MODE_NARROWBAND, N_("Narrowband ~8 kHz (telephone quality)"), NULL },
1209 { MODE_WIDEBAND, N_("Wideband ~16 kHz"), NULL },
1210 #if SPEEX_NB_MODES > 2
1211 { MODE_ULTRAWIDEBAND, N_("Ultra-wideband 32-48 kHz"), NULL },
1212 #endif
1213 { 0, NULL, NULL }
1214 };
1215
1216 static sw_choice feature_choices[] = {
1217 #ifdef HAVE_SPEEX_BETA4
1218 { 0, N_("Constant bitrate (CBR) with no features"),
1219 NULL
1220 },
1221 { FEAT_VAD, N_("CBR with Voice Activity Detection (VAD)"),
1222 N_("VAD generates low bitrate comfort noise to replace non-speech")
1223 },
1224 { FEAT_VAD | FEAT_DTX,
1225 N_("CBR with VAD and Discontinuous Transmission (DTX)"),
1226 N_("DTX marks extended pauses with a minimum bitrate signal")
1227 },
1228 { FEAT_VBR | FEAT_VAD,
1229 N_("Variable bitrate (VBR) with VAD"),
1230 N_("VBR allows the bitrate to adapt to the complexity of the speech; "
1231 "this selection uses VBR without DTX, which may improve performance "
1232 "compared to full VBR in the presence of background noise.")
1233 },
1234 { FEAT_VBR | FEAT_VAD | FEAT_DTX,
1235 N_("Variable bitrate (VBR) with all features"),
1236 N_("VBR allows the bitrate to adapt to the complexity of the speech, "
1237 "and handles pauses using VAD and DTX")
1238 },
1239 #else
1240 { 0, N_("Constant bitrate (CBR)"), NULL },
1241 { FEAT_VBR,
1242 N_("Variable bitrate (VBR)"),
1243 N_("VBR allows the bitrate to adapt to the complexity of the speech.")
1244 },
1245 #endif
1246 { 0, NULL, NULL }
1247 };
1248
1249 static void
speex_encode_options_update_cb(GtkWidget * widget,gpointer data)1250 speex_encode_options_update_cb (GtkWidget * widget, gpointer data)
1251 {
1252 GtkWidget * dialog;
1253 GtkWidget * br_checkbutton;
1254 GtkWidget * quality_label;
1255 GtkWidget * quality_hscale;
1256 GtkWidget * br_label;
1257 GtkWidget * br_entry;
1258 GtkWidget * br_units;
1259
1260 gboolean br;
1261 gint features;
1262
1263 dialog = gtk_widget_get_toplevel (widget);
1264
1265 /* Features */
1266 features =
1267 GPOINTER_TO_INT (g_object_get_data (G_OBJECT(dialog),
1268 "features_choice"));
1269
1270 /* Quality */
1271
1272 quality_label =
1273 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "quality_label"));
1274 quality_hscale =
1275 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "quality_hscale"));
1276
1277 /* Bitrate */
1278
1279 br_checkbutton =
1280 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "br_chb"));
1281 br = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(br_checkbutton));
1282
1283 br_label =
1284 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "br_label"));
1285 br_entry =
1286 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "br_entry"));
1287 br_units =
1288 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "br_units"));
1289
1290 gtk_widget_set_sensitive (br_label, br);
1291 gtk_widget_set_sensitive (br_entry, br);
1292 gtk_widget_set_sensitive (br_units, br);
1293 gtk_widget_set_sensitive (quality_label, !br);
1294 gtk_widget_set_sensitive (quality_hscale, !br);
1295
1296 if (features & FEAT_VBR) {
1297 gtk_scale_set_digits (GTK_SCALE (quality_hscale), 1);
1298 gtk_label_set_text (GTK_LABEL(br_label), _("Average bitrate"));
1299 } else {
1300 gtk_scale_set_digits (GTK_SCALE (quality_hscale), 0);
1301 gtk_label_set_text (GTK_LABEL(br_label), _("Maximum bitrate"));
1302 }
1303
1304 }
1305
1306 static void
speex_encode_options_mode_cb(GtkWidget * widget,gpointer data)1307 speex_encode_options_mode_cb (GtkWidget * widget, gpointer data)
1308 {
1309 GtkWidget * dialog = GTK_WIDGET (data);
1310 int mode;
1311
1312 mode = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(widget), "default"));
1313
1314 g_object_set_data (G_OBJECT(dialog), "mode_choice",
1315 GINT_TO_POINTER(mode));
1316 }
1317
1318 static void
speex_encode_options_mode_auto_cb(GtkWidget * widget,gpointer data)1319 speex_encode_options_mode_auto_cb (GtkWidget * widget, gpointer data)
1320 {
1321 sw_sample * sample = (sw_sample *)data;
1322 sw_format * f = sample->sounddata->format;
1323 GtkWidget * dialog;
1324 GtkOptionMenu * option_menu;
1325 int mode;
1326
1327 dialog = gtk_widget_get_toplevel (widget);
1328 option_menu =
1329 GTK_OPTION_MENU(g_object_get_data (G_OBJECT(dialog), "mode_menu"));
1330
1331 #if (SPEEX_NB_MODES > 2)
1332 if (f->rate >= 32000) {
1333 mode = MODE_ULTRAWIDEBAND;
1334 } else
1335 #endif
1336 if (f->rate >= 16000) {
1337 mode = MODE_WIDEBAND;
1338 } else {
1339 mode = MODE_NARROWBAND;
1340 }
1341
1342 gtk_option_menu_set_history (option_menu, mode);
1343 g_object_set_data (G_OBJECT(dialog), "mode_choice",
1344 GINT_TO_POINTER(mode));
1345 }
1346
1347 static void
speex_encode_options_set_features(GtkWidget * dialog,int features)1348 speex_encode_options_set_features (GtkWidget * dialog, int features)
1349 {
1350 GtkOptionMenu * option_menu;
1351 int i;
1352
1353 option_menu =
1354 GTK_OPTION_MENU(g_object_get_data (G_OBJECT(dialog), "features_menu"));
1355
1356 for (i = 0; feature_choices[i].name != NULL; i++) {
1357 if (feature_choices[i].number == features)
1358 gtk_option_menu_set_history (option_menu, i);
1359 }
1360
1361 g_object_set_data (G_OBJECT(dialog), "features_choice",
1362 GINT_TO_POINTER(features));
1363 }
1364
1365 static void
speex_encode_options_features_cb(GtkWidget * widget,gpointer data)1366 speex_encode_options_features_cb (GtkWidget * widget, gpointer data)
1367 {
1368 GtkWidget * dialog = GTK_WIDGET (data);
1369 int features;
1370
1371 features = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(widget), "default"));
1372
1373 g_object_set_data (G_OBJECT(dialog), "features_choice",
1374 GINT_TO_POINTER(features));
1375
1376 speex_encode_options_update_cb (dialog, data);
1377 }
1378
1379
1380 static void
speex_encode_options_reset_cb(GtkWidget * widget,gpointer data)1381 speex_encode_options_reset_cb (GtkWidget * widget, gpointer data)
1382 {
1383 GtkWidget * dialog;
1384
1385 GtkObject * adj;
1386 int * i, features, quality, complexity, framepack;
1387
1388 dialog = gtk_widget_get_toplevel (widget);
1389
1390 /* Mode menu */
1391 speex_encode_options_mode_auto_cb (widget, data);
1392
1393 /* Features menu */
1394 i = prefs_get_int (FEATURES_KEY);
1395
1396 if (i == NULL) {
1397 features = DEFAULT_FEATURES;
1398 } else {
1399 features = *i;
1400 }
1401
1402 speex_encode_options_set_features (dialog, features);
1403
1404 /* Quality */
1405
1406 adj = GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "quality_adj"));
1407
1408 i = prefs_get_int (QUALITY_KEY);
1409
1410 if (i == NULL) {
1411 quality = DEFAULT_QUALITY;
1412 } else {
1413 quality = *i;
1414 }
1415
1416 gtk_adjustment_set_value (GTK_ADJUSTMENT(adj), (float)quality);
1417
1418 /* Complexity */
1419
1420 adj = GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "complexity_adj"));
1421
1422 i = prefs_get_int (COMPLEXITY_KEY);
1423
1424 if (i == NULL) {
1425 complexity = DEFAULT_COMPLEXITY;
1426 } else {
1427 complexity = *i;
1428 }
1429
1430 gtk_adjustment_set_value (GTK_ADJUSTMENT(adj), (float)complexity);
1431
1432 /* Framepack */
1433
1434 adj = GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "framepack_adj"));
1435
1436 i = prefs_get_int (FRAMEPACK_KEY);
1437
1438 if (i == NULL) {
1439 framepack = DEFAULT_FRAMEPACK;
1440 } else {
1441 framepack = *i;
1442 }
1443
1444 gtk_adjustment_set_value (GTK_ADJUSTMENT(adj), (float)framepack);
1445
1446 speex_encode_options_update_cb (widget, data);
1447 }
1448
1449 static void
speex_encode_options_default_cb(GtkWidget * widget,gpointer data)1450 speex_encode_options_default_cb (GtkWidget * widget, gpointer data)
1451 {
1452 GtkWidget * dialog;
1453 GtkObject * quality_adj;
1454 GtkObject * complexity_adj;
1455 GtkObject * framepack_adj;
1456
1457 dialog = gtk_widget_get_toplevel (widget);
1458
1459 /* Mode menu */
1460 speex_encode_options_mode_auto_cb (widget, data);
1461
1462 /* Features menu */
1463 speex_encode_options_set_features (dialog, DEFAULT_FEATURES);
1464
1465 /* Quality */
1466 quality_adj =
1467 GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "quality_adj"));
1468 gtk_adjustment_set_value (GTK_ADJUSTMENT(quality_adj), DEFAULT_QUALITY);
1469
1470 /* Complexity */
1471 complexity_adj =
1472 GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "complexity_adj"));
1473 gtk_adjustment_set_value (GTK_ADJUSTMENT(complexity_adj),
1474 DEFAULT_COMPLEXITY);
1475
1476 /* Framepack */
1477 framepack_adj =
1478 GTK_OBJECT(g_object_get_data (G_OBJECT(dialog), "framepack_adj"));
1479 gtk_adjustment_set_value (GTK_ADJUSTMENT(framepack_adj), DEFAULT_FRAMEPACK);
1480
1481 speex_encode_options_update_cb (widget, data);
1482 }
1483
1484
1485 static void
remember_serialno_clicked_cb(GtkWidget * widget,gpointer data)1486 remember_serialno_clicked_cb (GtkWidget * widget, gpointer data)
1487 {
1488 sw_sample * sample = (sw_sample *)data;
1489 gboolean active;
1490
1491 active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget));
1492
1493 if (active) {
1494 sample_set_tmp_message (sample, _("Hack the planet!"));
1495 } else {
1496 sample_clear_tmp_message (sample);
1497 }
1498 }
1499
1500 static gboolean
randomise_serialno(gpointer data)1501 randomise_serialno (gpointer data)
1502 {
1503 GtkWidget * entry = (GtkWidget *)data;
1504 gchar * new_text;
1505
1506 new_text = g_strdup_printf ("%ld", random ());
1507 gtk_entry_set_text (GTK_ENTRY (entry), new_text);
1508 g_free (new_text);
1509
1510 return TRUE;
1511 }
1512
1513 static void
randomise_serialno_pressed_cb(GtkWidget * widget,gpointer data)1514 randomise_serialno_pressed_cb (GtkWidget * widget, gpointer data)
1515 {
1516 GtkWidget * dialog;
1517 GtkWidget * checkbutton;
1518 gint tag;
1519
1520 dialog = gtk_widget_get_toplevel (widget);
1521
1522 checkbutton =
1523 GTK_WIDGET(g_object_get_data (G_OBJECT(dialog), "rem_serialno_chb"));
1524 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), FALSE);
1525
1526 tag = gtk_timeout_add (30, randomise_serialno, data);
1527 g_object_set_data (G_OBJECT(widget), "tag", GINT_TO_POINTER(tag));
1528 }
1529
1530 static void
randomise_serialno_released_cb(GtkWidget * widget,gpointer data)1531 randomise_serialno_released_cb (GtkWidget * widget, gpointer data)
1532 {
1533 gint tag;
1534
1535 tag = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(widget), "tag"));
1536 gtk_timeout_remove (tag);
1537 }
1538
1539
1540
1541 static GtkWidget *
create_speex_encoding_options_dialog(sw_sample * sample,char * pathname)1542 create_speex_encoding_options_dialog (sw_sample * sample, char * pathname)
1543 {
1544 GtkWidget * dialog;
1545 GtkWidget * ok_button, * button;
1546 GtkWidget * main_vbox;
1547 GtkWidget * ebox;
1548 GtkWidget * vbox;
1549 GtkWidget * hbox, * hbox2;
1550 GtkWidget * option_menu;
1551 GtkWidget * menu;
1552 GtkWidget * menuitem;
1553 GtkWidget * table;
1554 GtkWidget * label;
1555 GtkWidget * pixmap;
1556
1557 GtkWidget * notebook;
1558
1559 GtkWidget * checkbutton;
1560 GtkObject * quality_adj;
1561 GtkWidget * quality_hscale;
1562 GtkObject * complexity_adj;
1563 GtkWidget * complexity_hscale;
1564 GtkObject * framepack_adj;
1565 GtkWidget * framepack_spin;
1566
1567 GtkWidget * entry;
1568
1569 GtkWidget * separator;
1570 GtkTooltips * tooltips;
1571 GtkWidget *speex_logo;
1572
1573 /* GtkStyle * style; */
1574
1575 int i;
1576 long * l;
1577
1578 dialog = gtk_dialog_new ();
1579 gtk_window_set_title (GTK_WINDOW(dialog),
1580 _("Sweep: Speex save options"));
1581 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
1582 sweep_set_window_icon(GTK_WINDOW(dialog));
1583
1584 attach_window_close_accel(GTK_WINDOW(dialog));
1585
1586 g_object_set_data (G_OBJECT(dialog), "pathname", pathname);
1587
1588 main_vbox = GTK_DIALOG(dialog)->vbox;
1589
1590 ebox = gtk_event_box_new ();
1591 gtk_box_pack_start (GTK_BOX(main_vbox), ebox, FALSE, TRUE, 0);
1592 gtk_widget_set_style (ebox, style_bw);
1593 gtk_widget_show (ebox);
1594
1595 vbox = gtk_vbox_new (FALSE, 0);
1596 gtk_container_add (GTK_CONTAINER(ebox), vbox);
1597 gtk_widget_show (vbox);
1598
1599 /* Ogg Speex pixmaps */
1600
1601 hbox = gtk_hbox_new (FALSE, 0);
1602 gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1603 gtk_container_set_border_width (GTK_CONTAINER(hbox), 4);
1604 gtk_widget_show (hbox);
1605
1606 speex_logo = create_widget_from_xpm (dialog, speex_logo_xpm);
1607 gtk_box_pack_start (GTK_BOX(hbox), speex_logo, FALSE, FALSE, 0);
1608 gtk_widget_show (speex_logo);
1609
1610 /* filename */
1611
1612
1613 /* worth changing this over to pango?
1614
1615 style = gtk_style_new ();
1616 gdk_font_unref (style->font);
1617 style->font =
1618 gdk_font_load("-*-helvetica-medium-r-normal-*-*-180-*-*-*-*-*-*");
1619 gtk_widget_push_style (style);
1620 */
1621 label = gtk_label_new (g_basename (pathname));
1622 gtk_box_pack_start (GTK_BOX(vbox), label, TRUE, FALSE, 0);
1623 gtk_widget_show (label);
1624
1625 /* gtk_widget_pop_style (); */
1626
1627 notebook = gtk_notebook_new ();
1628 gtk_box_pack_start (GTK_BOX(main_vbox), notebook, TRUE, TRUE, 4);
1629 gtk_widget_show (notebook);
1630
1631 label = gtk_label_new (_("Speex encoding"));
1632
1633 vbox = gtk_vbox_new (FALSE, 0);
1634 gtk_notebook_append_page (GTK_NOTEBOOK(notebook), vbox, label);
1635 gtk_container_set_border_width (GTK_CONTAINER(vbox), 4);
1636 gtk_widget_show (vbox);
1637
1638 /* Mode */
1639
1640 hbox = gtk_hbox_new (FALSE, 4);
1641 gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, TRUE, 4);
1642 gtk_widget_show (hbox);
1643
1644 label = gtk_label_new (_("Mode:"));
1645 gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
1646 gtk_widget_show (label);
1647
1648 option_menu = gtk_option_menu_new ();
1649 gtk_box_pack_start (GTK_BOX (hbox), option_menu, TRUE, TRUE, 4);
1650 gtk_widget_show (option_menu);
1651
1652 menu = gtk_menu_new ();
1653
1654 for (i = 0; mode_choices[i].name != NULL; i++) {
1655 menuitem =
1656 gtk_menu_item_new_with_label (_(mode_choices[i].name));
1657 gtk_menu_append (GTK_MENU(menu), menuitem);
1658 g_object_set_data (G_OBJECT(menuitem), "default",
1659 GINT_TO_POINTER(mode_choices[i].number));
1660 gtk_widget_show (menuitem);
1661
1662 g_signal_connect (G_OBJECT(menuitem), "activate",
1663 G_CALLBACK(speex_encode_options_mode_cb),
1664 dialog);
1665 }
1666 gtk_option_menu_set_menu (GTK_OPTION_MENU(option_menu), menu);
1667
1668 g_object_set_data (G_OBJECT(dialog), "mode_menu", option_menu);
1669
1670 button = gtk_button_new_with_label (_("Auto"));
1671 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 4);
1672 g_signal_connect (G_OBJECT(button), "clicked",
1673 G_CALLBACK(speex_encode_options_mode_auto_cb),
1674 sample);
1675 gtk_widget_show (button);
1676
1677 tooltips = gtk_tooltips_new ();
1678 gtk_tooltips_set_tip (tooltips, button,
1679 _("Automatically select the encoding mode based on "
1680 "the sampling rate of the file."),
1681 NULL);
1682
1683 separator = gtk_hseparator_new ();
1684 gtk_box_pack_start (GTK_BOX(vbox), separator, FALSE, TRUE, 4);
1685 gtk_widget_show (separator);
1686
1687 /* Features */
1688
1689 option_menu = gtk_option_menu_new ();
1690 gtk_box_pack_start (GTK_BOX (vbox), option_menu, FALSE, FALSE, 4);
1691 gtk_widget_show (option_menu);
1692
1693 menu = gtk_menu_new ();
1694
1695 for (i = 0; feature_choices[i].name != NULL; i++) {
1696 menuitem =
1697 gtk_menu_item_new_with_label (_(feature_choices[i].name));
1698 gtk_menu_append (GTK_MENU(menu), menuitem);
1699 g_object_set_data (G_OBJECT(menuitem), "default",
1700 GINT_TO_POINTER(feature_choices[i].number));
1701 gtk_widget_show (menuitem);
1702
1703 g_signal_connect (G_OBJECT(menuitem), "activate",
1704 G_CALLBACK(speex_encode_options_features_cb),
1705 dialog);
1706
1707 if (feature_choices[i].desc != NULL) {
1708 tooltips = gtk_tooltips_new ();
1709 gtk_tooltips_set_tip (tooltips, menuitem, _(feature_choices[i].desc),
1710 NULL);
1711 }
1712 }
1713 gtk_option_menu_set_menu (GTK_OPTION_MENU(option_menu), menu);
1714
1715 g_object_set_data (G_OBJECT(dialog), "features_menu", option_menu);
1716
1717
1718 table = gtk_table_new (3, 2, TRUE);
1719 gtk_box_pack_start (GTK_BOX(vbox), table, FALSE, FALSE, 4);
1720 gtk_container_set_border_width (GTK_CONTAINER(table), 8);
1721 gtk_widget_show (table);
1722
1723 /* quality */
1724
1725 hbox = gtk_hbox_new (FALSE, 4);
1726 /*gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 4);*/
1727 gtk_table_attach (GTK_TABLE(table), hbox, 0, 1, 0, 1,
1728 GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1729 /*gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);*/
1730 gtk_widget_show (hbox);
1731
1732 label = gtk_label_new (_("Encoding quality:"));
1733 gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 4);
1734 gtk_widget_show (label);
1735
1736 g_object_set_data (G_OBJECT (dialog), "quality_label", label);
1737
1738 quality_adj = gtk_adjustment_new (DEFAULT_QUALITY, /* value */
1739 1.0, /* lower */
1740 11.0, /* upper */
1741 1.0, /* step incr */
1742 1.0, /* page incr */
1743 1.0 /* page size */
1744 );
1745
1746 {
1747 /* How sucky ... we create a vbox in order to center the hscale within
1748 * its allocation, thus actually lining it up with its label ...
1749 */
1750 GtkWidget * vbox_pants;
1751
1752 vbox_pants = gtk_vbox_new (FALSE, 0);
1753 /*gtk_box_pack_start (GTK_BOX(hbox), vbox_pants, TRUE, TRUE, 0);*/
1754 gtk_table_attach (GTK_TABLE(table), vbox_pants, 1, 2, 0, 1,
1755 GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1756 gtk_widget_show (vbox_pants);
1757
1758 quality_hscale = gtk_hscale_new (GTK_ADJUSTMENT(quality_adj));
1759 gtk_box_pack_start (GTK_BOX (vbox_pants), quality_hscale, TRUE, TRUE, 0);
1760 gtk_scale_set_draw_value (GTK_SCALE (quality_hscale), TRUE);
1761 gtk_scale_set_digits (GTK_SCALE (quality_hscale), 0);
1762 gtk_widget_set_usize (quality_hscale, gdk_screen_width() / 8, -1);
1763 gtk_widget_show (quality_hscale);
1764
1765 g_object_set_data (G_OBJECT (dialog), "quality_hscale",
1766 quality_hscale);
1767
1768 label = gtk_label_new (NULL);
1769 gtk_box_pack_start (GTK_BOX(vbox_pants), label, FALSE, FALSE, 0);
1770 gtk_widget_show (label);
1771 }
1772
1773 tooltips = gtk_tooltips_new ();
1774 gtk_tooltips_set_tip (tooltips, quality_hscale,
1775 _("Encoding quality between 0 (lowest quality, "
1776 "smallest file) and 10 (highest quality, largest "
1777 "file)."),
1778 NULL);
1779
1780 g_object_set_data (G_OBJECT (dialog), "quality_adj", quality_adj);
1781
1782 /* Bit rate */
1783
1784 checkbutton =
1785 gtk_check_button_new_with_label (_("Enable bitrate management"));
1786 gtk_table_attach (GTK_TABLE(table), checkbutton, 0, 2, 1, 2,
1787 GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1788 gtk_widget_show (checkbutton);
1789
1790 g_signal_connect (G_OBJECT(checkbutton), "toggled",
1791 G_CALLBACK(speex_encode_options_update_cb),
1792 dialog);
1793
1794 g_object_set_data (G_OBJECT (dialog), "br_chb", checkbutton);
1795
1796 tooltips = gtk_tooltips_new ();
1797 gtk_tooltips_set_tip (tooltips, checkbutton,
1798 _("For non-VBR (constant bitrate) encoding, "
1799 "this sets the maximum bitrate."
1800 "For VBR encoding, this sets the average bitrate."),
1801 NULL);
1802
1803 label = gtk_label_new (_("Average bitrate"));
1804 gtk_table_attach (GTK_TABLE(table), label, 0, 1, 2, 3,
1805 GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1806 gtk_widget_show (label);
1807
1808 g_object_set_data (G_OBJECT (dialog), "br_label", label);
1809
1810 hbox = gtk_hbox_new (FALSE, 0);
1811 gtk_table_attach (GTK_TABLE(table), hbox, 1, 2, 2, 3,
1812 GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1813 gtk_widget_show (hbox);
1814
1815 entry = gtk_entry_new ();
1816 gtk_box_pack_start (GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1817 gtk_widget_show (entry);
1818
1819 g_object_set_data (G_OBJECT (dialog), "br_entry", entry);
1820
1821 label = gtk_label_new (_("bps"));
1822 gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 4);
1823 gtk_widget_show (label);
1824
1825 g_object_set_data (G_OBJECT (dialog), "br_units", label);
1826
1827 label = gtk_label_new (_("Extra"));
1828
1829 vbox = gtk_vbox_new (FALSE, 0);
1830 gtk_notebook_append_page (GTK_NOTEBOOK(notebook), vbox, label);
1831 gtk_container_set_border_width (GTK_CONTAINER(vbox), 4);
1832 gtk_widget_show (vbox);
1833
1834 table = gtk_table_new (2, 2, TRUE);
1835 gtk_box_pack_start (GTK_BOX(vbox), table, FALSE, FALSE, 4);
1836 /*gtk_container_set_border_width (GTK_CONTAINER(table), 8);*/
1837 gtk_widget_show (table);
1838
1839
1840 /* Encoder complexity */
1841
1842 hbox = gtk_hbox_new (FALSE, 4);
1843 /*gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 4);*/
1844 gtk_table_attach (GTK_TABLE(table), hbox, 0, 1, 0, 1,
1845 GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1846 /*gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);*/
1847 gtk_widget_show (hbox);
1848
1849 label = gtk_label_new (_("Encoding complexity:"));
1850 gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 4);
1851 gtk_widget_show (label);
1852
1853 complexity_adj = gtk_adjustment_new (DEFAULT_COMPLEXITY, /* value */
1854 1.0, /* lower */
1855 11.0, /* upper */
1856 1.0, /* step incr */
1857 1.0, /* page incr */
1858 1.0 /* page size */
1859 );
1860
1861 {
1862 /* How sucky ... we create a vbox in order to center the hscale within
1863 * its allocation, thus actually lining it up with its label ...
1864 */
1865 GtkWidget * vbox_pants;
1866
1867 vbox_pants = gtk_vbox_new (FALSE, 0);
1868 /*gtk_box_pack_start (GTK_BOX(hbox), vbox_pants, TRUE, TRUE, 0);*/
1869 gtk_table_attach (GTK_TABLE(table), vbox_pants, 1, 2, 0, 1,
1870 GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1871 gtk_widget_show (vbox_pants);
1872
1873 complexity_hscale = gtk_hscale_new (GTK_ADJUSTMENT(complexity_adj));
1874 gtk_box_pack_start (GTK_BOX (vbox_pants), complexity_hscale,
1875 TRUE, TRUE, 0);
1876 gtk_scale_set_draw_value (GTK_SCALE (complexity_hscale), TRUE);
1877 gtk_scale_set_digits (GTK_SCALE (complexity_hscale), 0);
1878 gtk_widget_set_usize (complexity_hscale, gdk_screen_width() / 8, -1);
1879 gtk_widget_show (complexity_hscale);
1880
1881 label = gtk_label_new (NULL);
1882 gtk_box_pack_start (GTK_BOX(vbox_pants), label, FALSE, FALSE, 0);
1883 gtk_widget_show (label);
1884 }
1885
1886 tooltips = gtk_tooltips_new ();
1887 gtk_tooltips_set_tip (tooltips, complexity_hscale,
1888 _("This sets the encoding speed/quality tradeoff "
1889 "between 0 (faster encoding) "
1890 "and 10 (slower encoding)"),
1891 NULL);
1892
1893 g_object_set_data (G_OBJECT (dialog), "complexity_adj", complexity_adj);
1894
1895 /* Frames per packet */
1896
1897 hbox = gtk_hbox_new (FALSE, 4);
1898 /*gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 4);*/
1899 gtk_table_attach (GTK_TABLE(table), hbox, 0, 1, 1, 2,
1900 GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1901 /*gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);*/
1902 gtk_widget_show (hbox);
1903
1904 label = gtk_label_new (_("Speex frames per Ogg packet:"));
1905 gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 4);
1906 gtk_widget_show (label);
1907
1908 hbox = gtk_hbox_new (FALSE, 4);
1909 /*gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 4);*/
1910 gtk_table_attach (GTK_TABLE(table), hbox, 1, 2, 1, 2,
1911 GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
1912 /*gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);*/
1913 gtk_widget_show (hbox);
1914
1915 framepack_adj = gtk_adjustment_new (DEFAULT_FRAMEPACK, /* value */
1916 1.0, /* lower */
1917 10.0, /* upper */
1918 1.0, /* step incr */
1919 1.0, /* page incr */
1920 1.0 /* page size */
1921 );
1922
1923 framepack_spin = gtk_spin_button_new (GTK_ADJUSTMENT(framepack_adj),
1924 1.0, 0);
1925 gtk_box_pack_start (GTK_BOX (hbox), framepack_spin, FALSE, FALSE, 0);
1926 gtk_widget_show (framepack_spin);
1927
1928 tooltips = gtk_tooltips_new ();
1929 gtk_tooltips_set_tip (tooltips, framepack_spin,
1930 _("Number of Speex frames to pack into each Ogg "
1931 "packet. Higher values save space at low "
1932 "bitrates."),
1933 NULL);
1934
1935 g_object_set_data (G_OBJECT (dialog), "framepack_adj", framepack_adj);
1936
1937 /* Remember / Reset */
1938
1939 hbox = gtk_hbox_new (FALSE, 4);
1940 gtk_box_pack_start (GTK_BOX(main_vbox), hbox, FALSE, FALSE, 4);
1941 gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);
1942 gtk_widget_show (hbox);
1943
1944 checkbutton =
1945 gtk_check_button_new_with_label (_("Remember these encoding options"));
1946 gtk_box_pack_start (GTK_BOX (hbox), checkbutton, TRUE, TRUE, 0);
1947 gtk_widget_show (checkbutton);
1948
1949 g_object_set_data (G_OBJECT (dialog), "rem_encode_chb", checkbutton);
1950
1951 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), TRUE);
1952
1953 hbox2 = gtk_hbox_new (TRUE, 4);
1954 gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, TRUE, 0);
1955 gtk_widget_show (hbox2);
1956
1957 button = gtk_button_new_with_label (_("Reset"));
1958 gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, TRUE, 4);
1959 g_signal_connect (G_OBJECT(button), "clicked",
1960 G_CALLBACK(speex_encode_options_reset_cb), sample);
1961 gtk_widget_show (button);
1962
1963 tooltips = gtk_tooltips_new ();
1964 gtk_tooltips_set_tip (tooltips, button,
1965 _("Reset to the last remembered encoding options."),
1966 NULL);
1967
1968 /* Call the reset callback now to set remembered options */
1969 speex_encode_options_reset_cb (button, sample);
1970
1971 button = gtk_button_new_with_label (_("Defaults"));
1972 gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, TRUE, 4);
1973 g_signal_connect (G_OBJECT(button), "clicked",
1974 G_CALLBACK(speex_encode_options_default_cb),
1975 sample);
1976 gtk_widget_show (button);
1977
1978 tooltips = gtk_tooltips_new ();
1979 gtk_tooltips_set_tip (tooltips, button,
1980 _("Automatically select best encoding options for this file."),
1981 NULL);
1982
1983 /* Ogg stream */
1984
1985 label = gtk_label_new (_("Ogg stream"));
1986
1987 vbox = gtk_vbox_new (FALSE, 4);
1988 gtk_notebook_append_page (GTK_NOTEBOOK(notebook), vbox, label);
1989 gtk_widget_show (vbox);
1990
1991 /* Stream serial no. */
1992
1993 hbox = gtk_hbox_new (FALSE, 0);
1994 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1995 gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);
1996 gtk_widget_show (hbox);
1997
1998 label = gtk_label_new (_("Ogg stream serial number:"));
1999 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
2000 gtk_widget_show (label);
2001
2002 entry = gtk_entry_new ();
2003 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 4);
2004 gtk_widget_show (entry);
2005
2006 g_object_set_data (G_OBJECT (dialog), "serialno_entry", entry);
2007
2008 /* Remember serialno ? */
2009
2010 hbox = gtk_hbox_new (FALSE, 0);
2011 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
2012 gtk_widget_show (hbox);
2013
2014 button = gtk_hseparator_new ();
2015 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 8);
2016 gtk_widget_show (button);
2017
2018 checkbutton =
2019 gtk_check_button_new_with_label (_("Remember this serial number"));
2020 gtk_box_pack_start (GTK_BOX (hbox), checkbutton, FALSE, TRUE, 0);
2021 gtk_widget_show (checkbutton);
2022
2023 g_signal_connect (G_OBJECT(checkbutton), "toggled",
2024 G_CALLBACK(remember_serialno_clicked_cb),
2025 sample);
2026
2027 tooltips = gtk_tooltips_new ();
2028 gtk_tooltips_set_tip (tooltips, checkbutton,
2029 _("Remember this serial number for future re-use.\n"
2030 "USE OF THIS OPTION IS NOT RECOMMENDED.\n"
2031 "Each encoded file should have a different "
2032 "serial number; "
2033 "re-use of Ogg serial numbers in different files "
2034 "may create incompatabilities with streaming "
2035 "applications. "
2036 "This option is provided for bitstream engineering "
2037 "purposes only.\n"
2038 "If this option is not checked, new serial numbers "
2039 "will be randomly generated for each file encoded."),
2040 NULL);
2041
2042 g_object_set_data (G_OBJECT (dialog), "rem_serialno_chb", checkbutton);
2043
2044 l = prefs_get_long (SERIALNO_KEY);
2045
2046 if (l == NULL) {
2047 randomise_serialno (entry);
2048 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), FALSE);
2049 } else {
2050 gtk_entry_set_text (GTK_ENTRY(entry), g_strdup_printf ("%ld", *l));
2051 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), TRUE);
2052 }
2053
2054 /* Randomise serialno! */
2055
2056 button = gtk_button_new_with_label (_("Randomize!"));
2057 gtk_container_set_border_width (GTK_CONTAINER(button), 64);
2058 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
2059 gtk_widget_show (button);
2060
2061 tooltips = gtk_tooltips_new ();
2062 gtk_tooltips_set_tip (tooltips, button,
2063 _("Generate a random serial number for the "
2064 "Ogg bitstream. The number will change while "
2065 "this button is held down."),
2066 NULL);
2067
2068 g_signal_connect (G_OBJECT(button), "pressed",
2069 G_CALLBACK(randomise_serialno_pressed_cb),
2070 entry);
2071
2072 g_signal_connect (G_OBJECT(button), "released",
2073 G_CALLBACK(randomise_serialno_released_cb),
2074 entry);
2075
2076 /* About */
2077
2078 label = gtk_label_new (_("About"));
2079
2080 ebox = gtk_event_box_new ();
2081 gtk_notebook_append_page (GTK_NOTEBOOK(notebook), ebox, label);
2082 gtk_widget_set_style (ebox, style_bw);
2083 gtk_widget_show (ebox);
2084
2085 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK(notebook), ebox,
2086 TRUE, TRUE, GTK_PACK_END);
2087
2088 vbox = gtk_vbox_new (FALSE, 16);
2089 gtk_container_add (GTK_CONTAINER(ebox), vbox);
2090 gtk_container_set_border_width (GTK_CONTAINER(vbox), 8);
2091 gtk_widget_show (vbox);
2092
2093 label =
2094 gtk_label_new (_("Speex is a high quality speech codec designed for\n"
2095 "voice over IP (VoIP) and file-based compression.\n"
2096 "It is free, open and unpatented."));
2097 gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
2098 gtk_widget_show (label);
2099
2100 hbox = gtk_hbox_new (FALSE, 16);
2101 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
2102 gtk_widget_show (hbox);
2103
2104 label =
2105 gtk_label_new (_("Ogg, Speex, Xiph.org Foundation and their logos\n"
2106 "are trademarks (tm) of the Xiph.org Foundation.\n"
2107 "Used with permission."));
2108 gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 8);
2109 gtk_widget_show (label);
2110
2111 pixmap = create_widget_from_xpm (dialog, xifish_xpm);
2112 gtk_box_pack_start (GTK_BOX(hbox), pixmap, FALSE, FALSE, 8);
2113 gtk_widget_show (pixmap);
2114
2115
2116 button = gtk_hseparator_new ();
2117 gtk_box_pack_start (GTK_BOX(vbox), button, FALSE, FALSE, 8);
2118 gtk_widget_show (button);
2119
2120 label = gtk_label_new (_("This user interface by Conrad Parker,\n"
2121 "Copyright (C) 2002 CSIRO Australia.\n\n"));
2122 gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
2123 gtk_widget_show (label);
2124
2125 /* OK */
2126
2127 ok_button = gtk_button_new_with_label (_("Save"));
2128 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (ok_button), GTK_CAN_DEFAULT);
2129 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), ok_button,
2130 TRUE, TRUE, 0);
2131 gtk_widget_show (ok_button);
2132 g_signal_connect (G_OBJECT(ok_button), "clicked",
2133 G_CALLBACK (speex_save_options_dialog_ok_cb),
2134 sample);
2135
2136 /* Cancel */
2137
2138 button = gtk_button_new_with_label (_("Don't save"));
2139 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (button), GTK_CAN_DEFAULT);
2140 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), button,
2141 TRUE, TRUE, 0);
2142 gtk_widget_show (button);
2143 g_signal_connect (G_OBJECT(button), "clicked",
2144 G_CALLBACK (speex_save_options_dialog_cancel_cb),
2145 sample);
2146
2147 gtk_widget_grab_default (ok_button);
2148
2149 return (dialog);
2150 }
2151
2152 int
speex_save_options_dialog(sw_sample * sample,char * pathname)2153 speex_save_options_dialog (sw_sample * sample, char * pathname)
2154 {
2155 GtkWidget * dialog;
2156
2157 dialog = create_speex_encoding_options_dialog (sample, pathname);
2158 gtk_widget_show (dialog);
2159
2160 return 0;
2161 }
2162
2163 #endif /* HAVE_SPEEX */
2164