summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deadbeef.h4
-rw-r--r--gtkplaylist.c5
-rw-r--r--junklib.c54
-rw-r--r--playlist.c55
-rw-r--r--playlist.h4
-rw-r--r--streamer.c52
6 files changed, 148 insertions, 26 deletions
diff --git a/deadbeef.h b/deadbeef.h
index 730cd14f..ddff5aed 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -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) {
diff --git a/junklib.c b/junklib.c
index 630fbbf7..a3dbd6dd 100644
--- a/junklib.c
+++ b/junklib.c
@@ -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;
}
diff --git a/playlist.c b/playlist.c
index 9e6da88b..feb7f789 100644
--- a/playlist.c
+++ b/playlist.c
@@ -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);
diff --git a/playlist.h b/playlist.h
index a084e087..e27b0df3 100644
--- a/playlist.h
+++ b/playlist.h
@@ -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
diff --git a/streamer.c b/streamer.c
index dd53fa6b..ceba12d7 100644
--- a/streamer.c
+++ b/streamer.c
@@ -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;
}
}