[SCM] libgroove/upstream: ability to set true peak on playlist items. closes #50
andrewrk-guest at users.alioth.debian.org
andrewrk-guest at users.alioth.debian.org
Tue May 13 03:19:10 UTC 2014
The following commit has been merged in the upstream branch:
commit 8582b8e71873d16bbb1755ac78a08a38118b03c5
Author: Andrew Kelley <superjoe30 at gmail.com>
Date: Sun May 11 16:23:54 2014 -0700
ability to set true peak on playlist items. closes #50
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 47e745c..52d85fc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
* fingerprinter: encode/decode return 0 on success, < 0 on error
* fingerprinter: info struct contains raw fingerprint instead of
compressed string. closes #61
+ * ability to set true peak on playlist items. closes #50
### Version 3.1.1 (2014-04-21)
diff --git a/example/fingerprint.c b/example/fingerprint.c
index ae769d2..dc9f215 100644
--- a/example/fingerprint.c
+++ b/example/fingerprint.c
@@ -38,7 +38,7 @@ int main(int argc, char * argv[]) {
fprintf(stderr, "Unable to open %s\n", arg);
continue;
}
- groove_playlist_insert(playlist, file, 1.0, NULL);
+ groove_playlist_insert(playlist, file, 1.0, 1.0, NULL);
}
}
diff --git a/example/playlist.c b/example/playlist.c
index debb275..0399579 100644
--- a/example/playlist.c
+++ b/example/playlist.c
@@ -45,7 +45,7 @@ int main(int argc, char * argv[]) {
fprintf(stderr, "Not queuing %s\n", arg);
continue;
}
- groove_playlist_insert(playlist, file, 1.0, NULL);
+ groove_playlist_insert(playlist, file, 1.0, 1.0, NULL);
}
}
groove_player_attach(player, playlist);
diff --git a/example/replaygain.c b/example/replaygain.c
index 8b4ab99..94eb9bc 100644
--- a/example/replaygain.c
+++ b/example/replaygain.c
@@ -33,7 +33,7 @@ int main(int argc, char * argv[]) {
fprintf(stderr, "Unable to open %s\n", filename);
continue;
}
- groove_playlist_insert(playlist, file, 1.0, NULL);
+ groove_playlist_insert(playlist, file, 1.0, 1.0, NULL);
}
struct GrooveLoudnessDetector *detector = groove_loudness_detector_create();
diff --git a/example/transcode.c b/example/transcode.c
index d4cafbb..5ed559b 100644
--- a/example/transcode.c
+++ b/example/transcode.c
@@ -50,7 +50,7 @@ int main(int argc, char * argv[]) {
fprintf(stderr, "Error opening input file %s\n", arg);
return 1;
}
- groove_playlist_insert(playlist, file, 1.0, NULL);
+ groove_playlist_insert(playlist, file, 1.0, 1.0, NULL);
}
}
if (!output_file_name)
diff --git a/groove/groove.h b/groove/groove.h
index 4f9c205..d441cf9 100644
--- a/groove/groove.h
+++ b/groove/groove.h
@@ -143,13 +143,27 @@ void groove_file_audio_format(struct GrooveFile *file,
/************* GroovePlaylist *************/
struct GroovePlaylistItem {
/* all fields are read-only. modify with methods below. */
- struct GroovePlaylistItem *prev;
+
struct GrooveFile *file;
- /* a volume adjustment in float format to apply to the file when it plays.
- * This is typically used for ReplayGain.
+
+ /* A volume adjustment in float format to apply to the file when it plays.
+ * This is typically used for loudness compensation, for example ReplayGain.
* To convert from dB to float, use exp(log(10) * 0.05 * dB_value)
*/
double gain;
+
+ /* The sample peak of this playlist item is assumed to be 1.0 in float
+ * format. If you know for certain that the peak is less than 1.0, you
+ * may set this value which may allow the volume adjustment to use
+ * a pure amplifier rather than a compressor. This results in slightly
+ * better audio quality.
+ */
+ double peak;
+
+ /* A GroovePlaylist is a doubly linked list. Use these fields to
+ * traverse the list.
+ */
+ struct GroovePlaylistItem *prev;
struct GroovePlaylistItem *next;
};
@@ -184,11 +198,13 @@ void groove_playlist_seek(struct GroovePlaylist *playlist,
/* once you add a file to the playlist, you must not destroy it until you first
* remove it from the playlist.
* next: the item to insert before. if NULL, you will append to the playlist.
- * gain: see GroovePlaylistItem structure. use 0 for no adjustment.
+ * gain: see GroovePlaylistItem structure. use 1.0 for no adjustment.
+ * peak: see GroovePlaylistItem structure. use 1.0 for no adjustment.
* returns the newly created playlist item.
*/
struct GroovePlaylistItem *groove_playlist_insert(
- struct GroovePlaylist *playlist, struct GrooveFile *file, double gain,
+ struct GroovePlaylist *playlist, struct GrooveFile *file,
+ double gain, double peak,
struct GroovePlaylistItem *next);
/* this will not call groove_file_close on item->file !
@@ -221,6 +237,9 @@ int groove_playlist_count(struct GroovePlaylist *playlist);
void groove_playlist_set_gain(struct GroovePlaylist *playlist,
struct GroovePlaylistItem *item, double gain);
+void groove_playlist_set_peak(struct GroovePlaylist *playlist,
+ struct GroovePlaylistItem *item, double peak);
+
/* value is in float format. defaults to 1.0 */
void groove_playlist_set_volume(struct GroovePlaylist *playlist, double volume);
diff --git a/groove/playlist.c b/groove/playlist.c
index 5ca8c2e..caf1025 100644
--- a/groove/playlist.c
+++ b/groove/playlist.c
@@ -73,6 +73,8 @@ struct GroovePlaylistPrivate {
struct GroovePlaylistItem *decode_head;
// desired volume for the volume filter
double volume;
+ // known true peak value
+ double peak;
// set to 1 to trigger a rebuild
int rebuild_filter_graph_flag;
// map audio format to list of sinks
@@ -81,8 +83,9 @@ struct GroovePlaylistPrivate {
struct SinkMap *sink_map;
int sink_map_count;
- // the value for volume that was used to construct the filter graph
+ // the value that was used to construct the filter graph
double filter_volume;
+ double filter_peak;
// only touched by decode_thread, tells whether we have sent the end_of_q_sentinel
int sent_end_of_q;
@@ -310,12 +313,18 @@ static int init_filter_graph(struct GroovePlaylist *playlist, struct GrooveFile
// save the volume value so we can compare later and check
// whether we have to reconstruct the graph
p->filter_volume = p->volume;
+ p->filter_peak = p->peak;
// if volume is < 1.0, create volume filter
// == 1.0, do not create a filter
// > 1.0, create a compand filter (for soft limiting)
double vol = p->volume;
+ // adjust for the known true peak of the playlist item. In other words, if
+ // we know that the song peaks at 0.8, and we want to amplify by 1.2, that
+ // comes out to 0.96 so we know that we can safely amplify by 1.2 even
+ // though it's greater than 1.0.
+ double amp_vol = vol * (p->peak > 1.0 ? 1.0 : p->peak);
if (vol < 0.0) vol = 0.0;
- if (vol < 1.0) {
+ if (amp_vol < 1.0) {
snprintf(p->strbuf, sizeof(p->strbuf), "volume=%f", vol);
av_log(NULL, AV_LOG_INFO, "volume: %s\n", p->strbuf);
err = avfilter_graph_create_filter(&p->volume_ctx, volume, NULL,
@@ -330,7 +339,7 @@ static int init_filter_graph(struct GroovePlaylist *playlist, struct GrooveFile
return err;
}
audio_src_ctx = p->volume_ctx;
- } else if (vol > 1.0) {
+ } else if (amp_vol > 1.0) {
double attack = 0.1;
double decay = 0.2;
const char *points = "-2/-2";
@@ -453,7 +462,8 @@ static int maybe_init_filter_graph(struct GroovePlaylist *playlist, struct Groov
p->in_sample_fmt != avctx->sample_fmt ||
p->in_time_base.num != time_base.num ||
p->in_time_base.den != time_base.den ||
- p->volume != p->filter_volume)
+ p->volume != p->filter_volume ||
+ p->peak != p->filter_peak)
{
return init_filter_graph(playlist, file);
}
@@ -626,6 +636,13 @@ static int audioq_purge(struct GrooveQueue *queue, void *obj) {
return buffer->item == item;
}
+static void update_playlist_volume(struct GroovePlaylist *playlist) {
+ struct GroovePlaylistPrivate *p = (struct GroovePlaylistPrivate *) playlist;
+ struct GroovePlaylistItem *item = p->decode_head;
+ p->volume = playlist->volume * item->gain;
+ p->peak = item->peak;
+}
+
// this thread is responsible for decoding and inserting buffers of decoded
// audio into each sink
static void *decode_thread(void *arg) {
@@ -656,7 +673,7 @@ static void *decode_thread(void *arg) {
struct GrooveFile *file = p->decode_head->file;
- p->volume = p->decode_head->gain * playlist->volume;
+ update_playlist_volume(playlist);
if (decode_one_frame(playlist, file) < 0) {
p->decode_head = p->decode_head->next;
@@ -968,8 +985,8 @@ void groove_playlist_seek(struct GroovePlaylist *playlist, struct GroovePlaylist
pthread_mutex_unlock(&p->decode_head_mutex);
}
-struct GroovePlaylistItem * groove_playlist_insert(struct GroovePlaylist *playlist, struct GrooveFile *file,
- double gain, struct GroovePlaylistItem *next)
+struct GroovePlaylistItem *groove_playlist_insert(struct GroovePlaylist *playlist,
+ struct GrooveFile *file, double gain, double peak, struct GroovePlaylistItem *next)
{
struct GroovePlaylistItem * item = av_mallocz(sizeof(struct GroovePlaylistItem));
if (!item)
@@ -978,6 +995,7 @@ struct GroovePlaylistItem * groove_playlist_insert(struct GroovePlaylist *playli
item->file = file;
item->next = next;
item->gain = gain;
+ item->peak = peak;
struct GroovePlaylistPrivate *p = (struct GroovePlaylistPrivate *) playlist;
struct GrooveFilePrivate *f = (struct GrooveFilePrivate *) file;
@@ -1092,7 +1110,20 @@ void groove_playlist_set_gain(struct GroovePlaylist *playlist, struct GroovePlay
pthread_mutex_lock(&p->decode_head_mutex);
item->gain = gain;
if (item == p->decode_head) {
- p->volume = playlist->volume * p->decode_head->gain;
+ update_playlist_volume(playlist);
+ }
+ pthread_mutex_unlock(&p->decode_head_mutex);
+}
+
+void groove_playlist_set_peak(struct GroovePlaylist *playlist, struct GroovePlaylistItem *item,
+ double peak)
+{
+ struct GroovePlaylistPrivate *p = (struct GroovePlaylistPrivate *) playlist;
+
+ pthread_mutex_lock(&p->decode_head_mutex);
+ item->peak = peak;
+ if (item == p->decode_head) {
+ update_playlist_volume(playlist);
}
pthread_mutex_unlock(&p->decode_head_mutex);
}
@@ -1119,7 +1150,8 @@ void groove_playlist_set_volume(struct GroovePlaylist *playlist, double volume)
pthread_mutex_lock(&p->decode_head_mutex);
playlist->volume = volume;
- p->volume = p->decode_head ? volume * p->decode_head->gain : volume;
+ if (p->decode_head)
+ update_playlist_volume(playlist);
pthread_mutex_unlock(&p->decode_head_mutex);
}
--
libgroove packaging
More information about the pkg-multimedia-commits
mailing list