comparison src/madplug/plugin.c @ 2341:59addab003d7

- reworked replaygain to use individual pre-gain for the files with RG info and the rest. - default pre-gain have been changed to +6dB for with RG, +0dB for the rest. - new clipping prevention feature using track peak information has been implemented. - reworked preferences dialog. widgets have been categorized by function and all changes will take effect immediately. and also, cancel button can reverts all changes have been done in the current session. - some keys in preferences have been changed.
author Yoshiki Yazawa <yaz@cc.rim.or.jp>
date Thu, 31 Jan 2008 15:22:15 +0900
parents 47d7a45b26a0
children fd8271f07747
comparison
equal deleted inserted replaced
2340:47d7a45b26a0 2341:59addab003d7
38 #include "tuple.h" 38 #include "tuple.h"
39 39
40 /* 40 /*
41 * Global variables 41 * Global variables
42 */ 42 */
43 struct audmad_config_t audmad_config; /**< global configuration */ 43 audmad_config_t *audmad_config; /**< global configuration */
44 GMutex *mad_mutex; 44 GMutex *mad_mutex;
45 GMutex *pb_mutex; 45 GMutex *pb_mutex;
46 GCond *mad_cond; 46 GCond *mad_cond;
47 47
48 /* 48 /*
77 * 77 *
78 * Return pointer within filename to its extenstion, or NULL if 78 * Return pointer within filename to its extenstion, or NULL if
79 * filename has no extension. 79 * filename has no extension.
80 * 80 *
81 */ 81 */
82 static gchar *extname(const char *filename) 82 static gchar *
83 extname(const char *filename)
83 { 84 {
84 gchar *ext = strrchr(filename, '.'); 85 gchar *ext = strrchr(filename, '.');
85 86
86 if (ext != NULL) 87 if (ext != NULL)
87 ++ext; 88 ++ext;
88 89
89 return ext; 90 return ext;
90 } 91 }
91 92
92 93
93 void audmad_config_compute(struct audmad_config_t *config) 94 void
95 audmad_config_compute(audmad_config_t *config)
94 { 96 {
95 /* set some config parameters by parsing text fields 97 /* set some config parameters by parsing text fields
96 (RG default gain, etc..) 98 (RG default gain, etc..)
97 */ 99 */
98 const gchar *text; 100 const gchar *text;
99 gdouble x; 101 gdouble x;
100 102
101 text = config->pregain_db; 103 text = config->replaygain.preamp0_db;
102 if ( text != NULL ) 104 if ( text != NULL )
103 x = g_strtod(text, NULL); 105 x = g_strtod(text, NULL);
104 else 106 else
105 x = 0; 107 x = 0;
106 config->pregain_scale = (x != 0) ? pow(10.0, x / 20) : 1; 108 config->replaygain.preamp0_scale = (x != 0) ? pow(10.0, x / 20) : 1;
107 AUDDBG("pregain=[%s] -> %g -> %g\n", text, x, config->pregain_scale); 109 AUDDBG("RG.preamp0=[%s] -> %g -> %g\n", text, x, config->preamp0_scale);
108 text = config->replaygain.default_db; 110
111 text = config->replaygain.preamp1_db;
109 if ( text != NULL ) 112 if ( text != NULL )
110 x = g_strtod(text, NULL); 113 x = g_strtod(text, NULL);
111 else 114 else
112 x = 0; 115 x = 0;
113 config->replaygain.default_scale = (x != 0) ? pow(10.0, x / 20) : 1; 116 config->replaygain.preamp1_scale = (x != 0) ? pow(10.0, x / 20) : 1;
114 AUDDBG("RG.default=[%s] -> %g -> %g\n", text, x, 117 AUDDBG("RG.preamp1=[%s] -> %g -> %g\n", text, x,
115 config->replaygain.default_scale); 118 config->replaygain.preamp1_scale);
116 } 119
117 120 text = config->replaygain.preamp2_db;
118 static void audmad_init() 121 if ( text != NULL )
122 x = g_strtod(text, NULL);
123 else
124 x = 0;
125 config->replaygain.preamp2_scale = (x != 0) ? pow(10.0, x / 20) : 1;
126 AUDDBG("RG.preamp2=[%s] -> %g -> %g\n", text, x,
127 config->replaygain.preamp2_scale);
128 }
129
130 static void
131 audmad_init()
119 { 132 {
120 ConfigDb *db = NULL; 133 ConfigDb *db = NULL;
121 134
122 audmad_config.fast_play_time_calc = TRUE; 135 audmad_config = g_malloc0(sizeof(audmad_config_t));
123 audmad_config.use_xing = TRUE; 136
124 audmad_config.dither = TRUE; 137 audmad_config->dither = TRUE;
125 audmad_config.sjis = FALSE; 138 audmad_config->force_reopen_audio = FALSE;
126 audmad_config.hard_limit = FALSE; 139 audmad_config->fast_play_time_calc = TRUE;
127 audmad_config.replaygain.enable = TRUE; 140 audmad_config->use_xing = TRUE;
128 audmad_config.replaygain.track_mode = FALSE; 141 audmad_config->sjis = FALSE;
129 audmad_config.title_override = FALSE; 142 audmad_config->show_avg_vbr_bitrate = TRUE;
130 audmad_config.show_avg_vbr_bitrate = TRUE; 143 audmad_config->replaygain.enable = TRUE;
131 audmad_config.force_reopen_audio = FALSE; 144 audmad_config->replaygain.track_mode = FALSE;
145 audmad_config->replaygain.anti_clip = FALSE;
146 audmad_config->replaygain.hard_limit = FALSE;
147 audmad_config->title_override = FALSE;
148
132 149
133 db = aud_cfg_db_open(); 150 db = aud_cfg_db_open();
134 if (db) { 151 if (db) {
152 //audio
153 aud_cfg_db_get_bool(db, "MAD", "dither", &audmad_config->dither);
154 aud_cfg_db_get_bool(db, "MAD", "force_reopen_audio",
155 &audmad_config->force_reopen_audio);
156
157 //metadata
135 aud_cfg_db_get_bool(db, "MAD", "fast_play_time_calc", 158 aud_cfg_db_get_bool(db, "MAD", "fast_play_time_calc",
136 &audmad_config.fast_play_time_calc); 159 &audmad_config->fast_play_time_calc);
137 aud_cfg_db_get_bool(db, "MAD", "use_xing", 160 aud_cfg_db_get_bool(db, "MAD", "use_xing",
138 &audmad_config.use_xing); 161 &audmad_config->use_xing);
139 aud_cfg_db_get_bool(db, "MAD", "dither", &audmad_config.dither); 162 aud_cfg_db_get_bool(db, "MAD", "sjis", &audmad_config->sjis);
140 aud_cfg_db_get_bool(db, "MAD", "sjis", &audmad_config.sjis); 163
141 aud_cfg_db_get_bool(db, "MAD", "hard_limit", 164 //misc
142 &audmad_config.hard_limit); 165 aud_cfg_db_get_bool(db, "MAD", "show_avg_vbr_bitrate",
143 aud_cfg_db_get_string(db, "MAD", "pregain_db", 166 &audmad_config->show_avg_vbr_bitrate);
144 &audmad_config.pregain_db); 167
168 //gain control
169 aud_cfg_db_get_string(db, "MAD", "RG.preamp0_db",
170 &audmad_config->replaygain.preamp0_db);
145 aud_cfg_db_get_bool(db, "MAD", "RG.enable", 171 aud_cfg_db_get_bool(db, "MAD", "RG.enable",
146 &audmad_config.replaygain.enable); 172 &audmad_config->replaygain.enable);
147 aud_cfg_db_get_bool(db, "MAD", "RG.track_mode", 173 aud_cfg_db_get_bool(db, "MAD", "RG.track_mode",
148 &audmad_config.replaygain.track_mode); 174 &audmad_config->replaygain.track_mode);
149 aud_cfg_db_get_string(db, "MAD", "RG.default_db", 175 aud_cfg_db_get_string(db, "MAD", "RG.preamp1_db",
150 &audmad_config.replaygain.default_db); 176 &audmad_config->replaygain.preamp1_db);
177 aud_cfg_db_get_string(db, "MAD", "RG.preamp2_db",
178 &audmad_config->replaygain.preamp2_db);
179 aud_cfg_db_get_bool(db, "MAD", "RG.anti_clip",
180 &audmad_config->replaygain.anti_clip);
181 aud_cfg_db_get_bool(db, "MAD", "RG.hard_limit",
182 &audmad_config->replaygain.hard_limit);
183
184 //text
151 aud_cfg_db_get_bool(db, "MAD", "title_override", 185 aud_cfg_db_get_bool(db, "MAD", "title_override",
152 &audmad_config.title_override); 186 &audmad_config->title_override);
153 aud_cfg_db_get_string(db, "MAD", "id3_format", 187 aud_cfg_db_get_string(db, "MAD", "id3_format",
154 &audmad_config.id3_format); 188 &audmad_config->id3_format);
155 aud_cfg_db_get_bool(db, "MAD", "show_avg_vbr_bitrate",
156 &audmad_config.show_avg_vbr_bitrate);
157 aud_cfg_db_get_bool(db, "MAD", "force_reopen_audio",
158 &audmad_config.force_reopen_audio);
159 189
160 aud_cfg_db_close(db); 190 aud_cfg_db_close(db);
161 } 191 }
162 192
163 mad_mutex = g_mutex_new(); 193 mad_mutex = g_mutex_new();
164 pb_mutex = g_mutex_new(); 194 pb_mutex = g_mutex_new();
165 mad_cond = g_cond_new(); 195 mad_cond = g_cond_new();
166 audmad_config_compute(&audmad_config); 196 audmad_config_compute(audmad_config);
167 197
168 if (!audmad_config.pregain_db) 198 if (!audmad_config->replaygain.preamp0_db)
169 audmad_config.pregain_db = g_strdup("+0.00"); 199 audmad_config->replaygain.preamp0_db = g_strdup("+0.00");
170 200
171 if (!audmad_config.replaygain.default_db) 201 if (!audmad_config->replaygain.preamp1_db)
172 audmad_config.replaygain.default_db = g_strdup("-9.00"); 202 audmad_config->replaygain.preamp1_db = g_strdup("+6.00");
173 203 if (!audmad_config->replaygain.preamp2_db)
174 if (!audmad_config.id3_format) 204 audmad_config->replaygain.preamp2_db = g_strdup("+0.00");
175 audmad_config.id3_format = g_strdup(""); 205
206 if (!audmad_config->id3_format)
207 audmad_config->id3_format = g_strdup("(none)");
176 208
177 init_gen_rand(4357); 209 init_gen_rand(4357);
178 210
179 aud_mime_set_plugin("audio/mpeg", mad_plugin); 211 aud_mime_set_plugin("audio/mpeg", mad_plugin);
180 } 212 }
181 213
182 static void audmad_cleanup() 214 static void
183 { 215 audmad_cleanup()
184 g_free(audmad_config.pregain_db); 216 {
185 g_free(audmad_config.replaygain.default_db); 217 g_free(audmad_config->replaygain.preamp0_db);
186 g_free(audmad_config.id3_format); 218 g_free(audmad_config->replaygain.preamp1_db);
187 219 g_free(audmad_config->replaygain.preamp2_db);
188 audmad_config.pregain_db = NULL; 220 g_free(audmad_config->id3_format);
189 audmad_config.replaygain.default_db = NULL; 221 g_free(audmad_config);
190 audmad_config.id3_format = NULL; 222
191
192 g_cond_free(mad_cond); 223 g_cond_free(mad_cond);
193 g_mutex_free(mad_mutex); 224 g_mutex_free(mad_mutex);
194 g_mutex_free(pb_mutex); 225 g_mutex_free(pb_mutex);
195 } 226 }
196 227
197 static gboolean mp3_head_check(guint32 head, gint *frameSize) 228 static gboolean
229 mp3_head_check(guint32 head, gint *frameSize)
198 { 230 {
199 gint version, layer, bitIndex, bitRate, sampleIndex, sampleRate, padding; 231 gint version, layer, bitIndex, bitRate, sampleIndex, sampleRate, padding;
200 232
201 /* http://www.mp3-tech.org/programmer/frame_header.html 233 /* http://www.mp3-tech.org/programmer/frame_header.html
202 * Bits 21-31 must be set (frame sync) 234 * Bits 21-31 must be set (frame sync)
280 return FALSE; 312 return FALSE;
281 313
282 return TRUE; 314 return TRUE;
283 } 315 }
284 316
285 static int mp3_head_convert(const guchar * hbuf) 317 static int
318 mp3_head_convert(const guchar * hbuf)
286 { 319 {
287 return ((unsigned long) hbuf[0] << 24) | 320 return ((unsigned long) hbuf[0] << 24) |
288 ((unsigned long) hbuf[1] << 16) | 321 ((unsigned long) hbuf[1] << 16) |
289 ((unsigned long) hbuf[2] << 8) | (unsigned long) hbuf[3]; 322 ((unsigned long) hbuf[2] << 8) | (unsigned long) hbuf[3];
290 } 323 }
291 324
292 // audacious vfs fast version 325 // audacious vfs fast version
293 static int audmad_is_our_fd(char *filename, VFSFile *fin) 326 static int
327 audmad_is_our_fd(char *filename, VFSFile *fin)
294 { 328 {
295 guint32 check; 329 guint32 check;
296 gchar *ext = extname(filename); 330 gchar *ext = extname(filename);
297 gint cyc = 0, chkcount = 0, chksize = 4096; 331 gint cyc = 0, chkcount = 0, chksize = 4096;
298 guchar buf[4]; 332 guchar buf[4];
374 408
375 return 1; 409 return 1;
376 } 410 }
377 411
378 // audacious vfs version 412 // audacious vfs version
379 static int audmad_is_our_file(char *filename) 413 static int
414 audmad_is_our_file(char *filename)
380 { 415 {
381 VFSFile *fin = NULL; 416 VFSFile *fin = NULL;
382 gint rtn; 417 gint rtn;
383 418
384 fin = aud_vfs_fopen(filename, "rb"); 419 fin = aud_vfs_fopen(filename, "rb");
390 aud_vfs_fclose(fin); 425 aud_vfs_fclose(fin);
391 426
392 return rtn; 427 return rtn;
393 } 428 }
394 429
395 static void audmad_stop(InputPlayback *playback) 430 static void
431 audmad_stop(InputPlayback *playback)
396 { 432 {
397 AUDDBG("f: audmad_stop\n"); 433 AUDDBG("f: audmad_stop\n");
398 g_mutex_lock(mad_mutex); 434 g_mutex_lock(mad_mutex);
399 info.playback = playback; 435 info.playback = playback;
400 g_mutex_unlock(mad_mutex); 436 g_mutex_unlock(mad_mutex);
415 451
416 } 452 }
417 AUDDBG("e: audmad_stop\n"); 453 AUDDBG("e: audmad_stop\n");
418 } 454 }
419 455
420 static void audmad_play_file(InputPlayback *playback) 456 static void
457 audmad_play_file(InputPlayback *playback)
421 { 458 {
422 gboolean rtn; 459 gboolean rtn;
423 gchar *url = playback->filename; 460 gchar *url = playback->filename;
424 461
425 #ifdef AUD_DEBUG 462 #ifdef AUD_DEBUG
434 g_message("error initialising input"); 471 g_message("error initialising input");
435 return; 472 return;
436 } 473 }
437 474
438 // remote access must use fast scan. 475 // remote access must use fast scan.
439 rtn = input_get_info(&info, aud_vfs_is_remote(url) ? TRUE : audmad_config.fast_play_time_calc); 476 rtn = input_get_info(&info, aud_vfs_is_remote(url) ? TRUE : audmad_config->fast_play_time_calc);
440 477
441 if (rtn == FALSE) { 478 if (rtn == FALSE) {
442 g_message("error reading input info"); 479 g_message("error reading input info");
443 /* 480 /*
444 * return; 481 * return;
454 decode_thread = g_thread_self(); 491 decode_thread = g_thread_self();
455 playback->set_pb_ready(playback); 492 playback->set_pb_ready(playback);
456 decode_loop(&info); 493 decode_loop(&info);
457 } 494 }
458 495
459 static void audmad_pause(InputPlayback *playback, short paused) 496 static void
497 audmad_pause(InputPlayback *playback, short paused)
460 { 498 {
461 g_mutex_lock(pb_mutex); 499 g_mutex_lock(pb_mutex);
462 info.playback = playback; 500 info.playback = playback;
463 g_mutex_unlock(pb_mutex); 501 g_mutex_unlock(pb_mutex);
464 playback->output->pause(paused); 502 playback->output->pause(paused);
465 } 503 }
466 504
467 static void audmad_mseek(InputPlayback *playback, gulong millisecond) 505 static void
506 audmad_mseek(InputPlayback *playback, gulong millisecond)
468 { 507 {
469 g_mutex_lock(pb_mutex); 508 g_mutex_lock(pb_mutex);
470 info.playback = playback; 509 info.playback = playback;
471 info.seek = millisecond; 510 info.seek = millisecond;
472 g_mutex_unlock(pb_mutex); 511 g_mutex_unlock(pb_mutex);
473 } 512 }
474 513
475 static void audmad_seek(InputPlayback *playback, gint time) 514 static void
515 audmad_seek(InputPlayback *playback, gint time)
476 { 516 {
477 audmad_mseek(playback, time * 1000); 517 audmad_mseek(playback, time * 1000);
478 } 518 }
479 519
480 /** 520 /**
494 if (input_init(&myinfo, url, NULL) == FALSE) { 534 if (input_init(&myinfo, url, NULL) == FALSE) {
495 AUDDBG("error initialising input\n"); 535 AUDDBG("error initialising input\n");
496 return; 536 return;
497 } 537 }
498 538
499 if (input_get_info(&myinfo, info.remote ? TRUE : audmad_config.fast_play_time_calc) == TRUE) { 539 if (input_get_info(&myinfo, info.remote ? TRUE : audmad_config->fast_play_time_calc) == TRUE) {
500 if(aud_tuple_get_string(myinfo.tuple, -1, "track-name")) 540 if(aud_tuple_get_string(myinfo.tuple, -1, "track-name"))
501 *title = g_strdup(aud_tuple_get_string(myinfo.tuple, -1, "track-name")); 541 *title = g_strdup(aud_tuple_get_string(myinfo.tuple, -1, "track-name"));
502 else 542 else
503 *title = g_strdup(url); 543 *title = g_strdup(url);
504 544
524 AUDDBG("audmad_fill_info(): error initialising input\n"); 564 AUDDBG("audmad_fill_info(): error initialising input\n");
525 return FALSE; 565 return FALSE;
526 } 566 }
527 567
528 info->fileinfo_request = FALSE; /* we don't need to read tuple again */ 568 info->fileinfo_request = FALSE; /* we don't need to read tuple again */
529 return input_get_info(info, aud_vfs_is_remote(fd->uri) ? TRUE : audmad_config.fast_play_time_calc); 569 return input_get_info(info, aud_vfs_is_remote(fd->uri) ? TRUE : audmad_config->fast_play_time_calc);
530 } 570 }
531 571
532 static void audmad_about() 572 static void
573 audmad_about()
533 { 574 {
534 static GtkWidget *aboutbox; 575 static GtkWidget *aboutbox;
535 gchar *scratch; 576 gchar *scratch;
536 577
537 if (aboutbox != NULL) 578 if (aboutbox != NULL)
566 607
567 /** 608 /**
568 * Display a GTK box containing the given error message. 609 * Display a GTK box containing the given error message.
569 * Taken from mpg123 plugin. 610 * Taken from mpg123 plugin.
570 */ 611 */
571 void audmad_error(char *error, ...) 612 void
613 audmad_error(char *error, ...)
572 { 614 {
573 #ifndef NOGUI 615 #ifndef NOGUI
574 if (!error_dialog) { 616 if (!error_dialog) {
575 va_list args; 617 va_list args;
576 char string[256]; 618 char string[256];
588 #endif /* !NOGUI */ 630 #endif /* !NOGUI */
589 } 631 }
590 632
591 extern void audmad_configure(); 633 extern void audmad_configure();
592 634
593 static void __set_and_free(Tuple *tuple, gint nfield, gchar *name, gchar *value) 635 static void
636 __set_and_free(Tuple *tuple, gint nfield, gchar *name, gchar *value)
594 { 637 {
595 aud_tuple_associate_string(tuple, nfield, name, value); 638 aud_tuple_associate_string(tuple, nfield, name, value);
596 g_free(value); 639 g_free(value);
597 } 640 }
598 641
599 // tuple stuff 642 // tuple stuff
600 static Tuple *__audmad_get_song_tuple(char *filename, VFSFile *fd) 643 static Tuple *
644 __audmad_get_song_tuple(char *filename, VFSFile *fd)
601 { 645 {
602 Tuple *tuple = NULL; 646 Tuple *tuple = NULL;
603 gchar *string = NULL; 647 gchar *string = NULL;
604 648
605 struct id3_file *id3file = NULL; 649 struct id3_file *id3file = NULL;
747 791
748 AUDDBG("e: mad: audmad_get_song_tuple\n"); 792 AUDDBG("e: mad: audmad_get_song_tuple\n");
749 return tuple; 793 return tuple;
750 } 794 }
751 795
752 static Tuple *audmad_get_song_tuple(char *filename) 796 static Tuple *
797 audmad_get_song_tuple(char *filename)
753 { 798 {
754 return __audmad_get_song_tuple(filename, NULL); 799 return __audmad_get_song_tuple(filename, NULL);
755 } 800 }
756 801
757 static Tuple *audmad_probe_for_tuple(char *filename, VFSFile *fd) 802 static Tuple *
803 audmad_probe_for_tuple(char *filename, VFSFile *fd)
758 { 804 {
759 if (!audmad_is_our_fd(filename, fd)) 805 if (!audmad_is_our_fd(filename, fd))
760 return NULL; 806 return NULL;
761 807
762 aud_vfs_rewind(fd); 808 aud_vfs_rewind(fd);