diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2009-09-23 23:14:17 +0200 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2009-09-23 23:14:17 +0200 |
commit | 90459ab8f2d1086fd2f164fd8a3f161708febb8a (patch) | |
tree | effd2bdb51bcda7c2364a24bd0f629c54eaa5c98 | |
parent | f91d372e4c3d08d59b6633560af491d56608cfcc (diff) |
replaygain (experimental)
-rw-r--r-- | deadbeef.h | 4 | ||||
-rw-r--r-- | gtkplaylist.c | 5 | ||||
-rw-r--r-- | junklib.c | 54 | ||||
-rw-r--r-- | playlist.c | 55 | ||||
-rw-r--r-- | playlist.h | 4 | ||||
-rw-r--r-- | streamer.c | 52 |
6 files changed, 148 insertions, 26 deletions
@@ -76,6 +76,10 @@ typedef struct { float playtime; // total playtime time_t started_timestamp; // result of calling time(NULL) const char *filetype; // e.g. MP3 or OGG + float replaygain_album_gain; + float replaygain_album_peak; + float replaygain_track_gain; + float replaygain_track_peak; } DB_playItem_t; // plugin types diff --git a/gtkplaylist.c b/gtkplaylist.c index 70daa6da..27685010 100644 --- a/gtkplaylist.c +++ b/gtkplaylist.c @@ -778,6 +778,11 @@ gtkpl_keypress (gtkplaylist_t *ps, int keyval, int state) { newscroll = ps->row - widget->allocation.height / rowheight + 1; } } + else if (keyval == GDK_r) { + extern int replaygain; + replaygain = 1-replaygain; + fprintf (stderr, "replaygain=%d\n", replaygain); + } else if (keyval == GDK_Up && ps->row > 0) { ps->row--; if (ps->row < ps->scrollpos) { @@ -850,18 +850,48 @@ junk_read_id3v2 (playItem_t *it, FILE *fp) { else if (!strcmp (frameid, "COMM")) { } else if (!strcmp (frameid, "TXXX")) { -#if 0 - uint32_t peak_amp = extract_i32 (readptr); - readptr += 4; - - uint16_t radio_rga = extract_i16 (readptr); - readptr += 2; - - uint16_t audiophile_rga = extract_i16 (readptr); - readptr += 2; - - trace ("got RGAD tag, %d %d %d\n", peak_amp, radio_rga, audiophile_rga); -#endif + if (sz < 2) { + trace ("TXXX frame is too short, skipped\n"); + readptr += sz; // bad tag + continue; + } + uint8_t *p = readptr; + uint8_t encoding = *p; + p++; + uint8_t *desc = p; + int desc_sz = 0; + while (*p && p - readptr < sz) { + p++; + desc_sz++; + } + p++; + if (p - readptr >= sz) { + trace ("bad TXXX frame, skipped\n"); + readptr += sz; // bad tag + continue; + } + char desc_s[desc_sz+2]; + id3v2_string_read (version_major, desc_s, desc_sz, unsync, desc); + //trace ("desc=%s\n", desc_s); + char value_s[readptr+sz-p+2]; + id3v2_string_read (version_major, value_s, readptr+sz-p, unsync, p); + //trace ("value=%s\n", value_s); + if (!strcasecmp (desc_s, "replaygain_album_gain")) { + it->replaygain_album_gain = atof (value_s); + trace ("%s=%s (%f)\n", desc_s, value_s, it->replaygain_album_gain); + } + else if (!strcasecmp (desc_s, "replaygain_album_peak")) { + it->replaygain_album_peak = atof (value_s); + trace ("%s=%s (%f)\n", desc_s, value_s, it->replaygain_album_peak); + } + else if (!strcasecmp (desc_s, "replaygain_track_gain")) { + it->replaygain_track_gain = atof (value_s); + trace ("%s=%s (%f)\n", desc_s, value_s, it->replaygain_track_gain); + } + else if (!strcasecmp (desc_s, "replaygain_track_peak")) { + it->replaygain_track_peak = atof (value_s); + trace ("%s=%s (%f)\n", desc_s, value_s, it->replaygain_track_peak); + } } readptr += sz; } @@ -40,8 +40,8 @@ #define PLAYLIST_MAJOR_VER 1 #define PLAYLIST_MINOR_VER 1 -//#define trace(...) { fprintf(stderr, __VA_ARGS__); } -#define trace(fmt,...) +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) #define SKIP_BLANK_CUE_TRACKS 1 @@ -606,6 +606,10 @@ pl_item_copy (playItem_t *out, playItem_t *it) { out->duration = it->duration; out->shufflerating = it->shufflerating; out->filetype = it->filetype; + out->replaygain_album_gain = it->replaygain_album_gain; + out->replaygain_album_peak = it->replaygain_album_peak; + out->replaygain_track_gain = it->replaygain_track_gain; + out->replaygain_track_peak = it->replaygain_track_peak; out->started_timestamp = it->started_timestamp; out->next[PL_MAIN] = it->next[PL_MAIN]; out->prev[PL_MAIN] = it->prev[PL_MAIN]; @@ -1054,6 +1058,19 @@ pl_save (const char *fname) { goto save_fail; } } + if (fwrite (&it->replaygain_album_gain, 1, 4, fp) != 4) { + goto save_fail; + } + if (fwrite (&it->replaygain_album_peak, 1, 4, fp) != 4) { + goto save_fail; + } + if (fwrite (&it->replaygain_track_gain, 1, 4, fp) != 4) { + goto save_fail; + } + if (fwrite (&it->replaygain_track_peak, 1, 4, fp) != 4) { + goto save_fail; + } + int16_t nm = 0; metaInfo_t *m; for (m = it->meta; m; m = m->next) { @@ -1111,13 +1128,13 @@ pl_load (const char *fname) { if (fread (&majorver, 1, 1, fp) != 1) { goto load_fail; } - if (majorver > PLAYLIST_MAJOR_VER) { + if (majorver != PLAYLIST_MAJOR_VER) { goto load_fail; } if (fread (&minorver, 1, 1, fp) != 1) { goto load_fail; } - if (minorver > PLAYLIST_MINOR_VER) { + if (minorver != PLAYLIST_MINOR_VER) { goto load_fail; } uint32_t cnt; @@ -1167,16 +1184,13 @@ pl_load (const char *fname) { goto load_fail; } it->tracknum = l; - if (minorver>=1) { - // dbpl-1.1 and later - // startsample - if (fread (&it->startsample, 1, 4, fp) != 4) { - goto load_fail; - } - // endsample - if (fread (&it->endsample, 1, 4, fp) != 4) { - goto load_fail; - } + // startsample + if (fread (&it->startsample, 1, 4, fp) != 4) { + goto load_fail; + } + // endsample + if (fread (&it->endsample, 1, 4, fp) != 4) { + goto load_fail; } // duration if (fread (&it->duration, 1, 4, fp) != 4) { @@ -1202,6 +1216,18 @@ pl_load (const char *fname) { } } } + if (fread (&it->replaygain_album_gain, 1, 4, fp) != 4) { + goto load_fail; + } + if (fread (&it->replaygain_album_peak, 1, 4, fp) != 4) { + goto load_fail; + } + if (fread (&it->replaygain_track_gain, 1, 4, fp) != 4) { + goto load_fail; + } + if (fread (&it->replaygain_track_peak, 1, 4, fp) != 4) { + goto load_fail; + } // printf ("loading file %s\n", it->fname); int16_t nm = 0; if (fread (&nm, 1, 2, fp) != 2) { @@ -1256,6 +1282,7 @@ pl_load (const char *fname) { fclose (fp); return 0; load_fail: + trace ("playlist load fail!\n"); fclose (fp); if (it) { pl_item_free (it); @@ -42,6 +42,10 @@ typedef struct playItem_s { float playtime; // total playtime time_t started_timestamp; // result of calling time(NULL) const char *filetype; // e.g. MP3 or OGG + float replaygain_album_gain; + float replaygain_album_peak; + float replaygain_track_gain; + float replaygain_track_peak; struct playItem_s *next[PL_MAX_ITERATORS]; // next item in linked list struct playItem_s *prev[PL_MAX_ITERATORS]; // prev item in linked list struct metaInfo_s *meta; // linked list storing metainfo @@ -34,6 +34,7 @@ #include "conf.h" #include "plugins.h" #include "optmath.h" +#include "volume.h" static intptr_t streamer_tid; static SRC_STATE *src; @@ -371,6 +372,52 @@ streamer_reset (int full) { // must be called when current song changes by exter src_reset (src); } +int replaygain = 0; + +static void +apply_replay_gain_int16 (playItem_t *it, char *bytes, int size) { + if (!replaygain) { + return; + } + if (it->replaygain_track_gain != 0) { + int vol = db_to_amp (str_streaming_song.replaygain_track_gain) * 1000; + int16_t *s = (int16_t*)bytes; + for (int j = 0; j < size/2; j++) { + int32_t sample = ((int32_t)*s) * vol / 1000; + if (sample > 0x7fff) { + sample = 0x7fff; + } + else if (sample < -0x8000) { + sample = -0x8000; + } + *s = (int16_t)sample; + s++; + } + } +} + +static void +apply_replay_gain_float32 (playItem_t *it, char *bytes, int size) { + if (!replaygain) { + return; + } + if (it->replaygain_track_gain != 0) { + float vol = db_to_amp (str_streaming_song.replaygain_track_gain); + float *s = (float*)bytes; + for (int j = 0; j < size/4; j++) { + float sample = ((float)*s) * vol; + if (sample > 1.f) { + sample = 1.f; + } + else if (sample < -1.f) { + sample = -1.f; + } + *s = sample; + s++; + } + } +} + // returns number of bytes been read static int streamer_read_async (char *bytes, int size) { @@ -393,10 +440,12 @@ streamer_read_async (char *bytes, int size) { if (decoder->info.channels == 2) { bytesread = decoder->read_int16 (bytes, size); codec_unlock (); + apply_replay_gain_int16 (&str_streaming_song, bytes, size); } else { bytesread = decoder->read_int16 (g_readbuffer, size/2); codec_unlock (); + apply_replay_gain_int16 (&str_streaming_song, g_readbuffer, size/2); for (i = 0; i < size/4; i++) { int16_t sample = (int16_t)(((int32_t)(((int16_t*)g_readbuffer)[i]))); ((int16_t*)bytes)[i*2+0] = sample; @@ -426,6 +475,7 @@ streamer_read_async (char *bytes, int size) { // } if (!decoder->read_float32) { bytesread = decoder->read_int16 (g_readbuffer, nbytes); + apply_replay_gain_int16 (&str_streaming_song, g_readbuffer, nbytes/2); } else { samplesize = 4; @@ -457,6 +507,7 @@ streamer_read_async (char *bytes, int size) { codec_lock (); bytesread = decoder->read_float32 (g_readbuffer, nbytes*2); codec_unlock (); + apply_replay_gain_float32 (&str_streaming_song, g_readbuffer, nbytes*2); nsamples = bytesread / (samplesize * nchannels) + codecleft; for (i = 0; i < (nsamples - codecleft); i++) { fbuffer[i*2+0] = ((float *)g_readbuffer)[i]; @@ -467,6 +518,7 @@ streamer_read_async (char *bytes, int size) { codec_lock (); bytesread = decoder->read_float32 ((char *)fbuffer, nbytes*2); codec_unlock (); + apply_replay_gain_float32 (&str_streaming_song, (char *)fbuffer, nbytes*2); nsamples = bytesread / (samplesize * nchannels) + codecleft; } } |