FS#11964. Rework replaygain handling to save metadata buffer and binsize. Remove string representation of replaygain and use a dedicated ftoa implementation for WPS/screen info.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29388 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Andree Buschmann 2011-02-24 19:10:59 +00:00
parent 6510973223
commit 71ceac0b74
12 changed files with 65 additions and 158 deletions

View file

@ -1475,22 +1475,22 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value)
case DSP_SET_TRACK_GAIN:
if (dsp == &AUDIO_DSP)
dsp_set_gain_var(&track_gain, value);
dsp_set_gain_var(&track_gain, convert_gain(value));
break;
case DSP_SET_ALBUM_GAIN:
if (dsp == &AUDIO_DSP)
dsp_set_gain_var(&album_gain, value);
dsp_set_gain_var(&album_gain, convert_gain(value));
break;
case DSP_SET_TRACK_PEAK:
if (dsp == &AUDIO_DSP)
dsp_set_gain_var(&track_peak, value);
dsp_set_gain_var(&track_peak, convert_gain(value));
break;
case DSP_SET_ALBUM_PEAK:
if (dsp == &AUDIO_DSP)
dsp_set_gain_var(&album_peak, value);
dsp_set_gain_var(&album_peak, convert_gain(value));
break;
default:

View file

@ -35,6 +35,7 @@
#include "sound.h"
#include "debug.h"
#include "cuesheet.h"
#include "replaygain.h"
#ifdef HAVE_LCD_CHARCELLS
#include "hwcompat.h"
#endif
@ -1305,8 +1306,8 @@ const char *get_token_value(struct gui_wps *gwps,
{
int type;
if (LIKELY(id3))
type = get_replaygain_mode(id3->track_gain_string != NULL,
id3->album_gain_string != NULL);
type = get_replaygain_mode(id3->track_gain != 0,
id3->album_gain != 0);
else
type = -1;
@ -1331,11 +1332,11 @@ const char *get_token_value(struct gui_wps *gwps,
/* due to above, coming here with !id3 shouldn't be possible */
case 2:
case 4:
strlcpy(buf, id3->track_gain_string, buf_size);
replaygain_itoa(buf, buf_size, id3->track_gain);
break;
case 3:
case 5:
strlcpy(buf, id3->album_gain_string, buf_size);
replaygain_itoa(buf, buf_size, id3->album_gain);
break;
}
return buf;

View file

@ -411,12 +411,6 @@ void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig)
entry->albumartist += offset;
if (entry->grouping)
entry->grouping += offset;
#if CONFIG_CODEC == SWCODEC
if (entry->track_gain_string)
entry->track_gain_string += offset;
if (entry->album_gain_string)
entry->album_gain_string += offset;
#endif
if (entry->mb_track_id)
entry->mb_track_id += offset;
}

View file

@ -283,13 +283,10 @@ struct mp3entry {
#endif
/* replaygain support */
#if CONFIG_CODEC == SWCODEC
char* track_gain_string;
char* album_gain_string;
long track_gain; /* 7.24 signed fixed point. 0 for no gain. */
long track_gain; /* s19.12 signed fixed point. 0 for no gain. */
long album_gain;
long track_peak; /* 7.24 signed fixed point. 0 for no peak. */
long track_peak; /* s19.12 signed fixed point. 0 for no peak. */
long album_peak;
#endif

View file

@ -456,18 +456,8 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
lseek(fd, length, SEEK_CUR);
}
} else if (!strncmp("replaygain_", utf8buf, 11)) {
char* value = id3buf;
int buf_len = id3buf_remaining;
int len;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
len = parse_replaygain(utf8buf, value, id3,
value, buf_len);
if (len == 0) {
/* Don't need to keep the value */
id3buf = value;
id3buf_remaining = buf_len;
}
parse_replaygain(utf8buf, id3buf, id3);
} else if (!strcmp("MusicBrainz/Track Id", utf8buf)) {
id3->mb_track_id = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);

View file

@ -370,14 +370,8 @@ static int parseuser( struct mp3entry* entry, char* tag, int bufferpos )
entry->albumartist = tag;
#if CONFIG_CODEC == SWCODEC
} else {
/* Calculate residual buffer size in bytes which can be used by
* parse_replaygain() to save the string representation of
* replaygain data.*/
length = sizeof(entry->id3v2buf) - (tag - entry->id3v2buf);
/* Call parse_replaygain(), returns length in bytes used by the
* string representation of replaygain data. */
length = parse_replaygain(tag, value, entry, tag, length);
/* Call parse_replaygain(). */
parse_replaygain(tag, value, entry);
#endif
}
}
@ -387,12 +381,11 @@ static int parseuser( struct mp3entry* entry, char* tag, int bufferpos )
#if CONFIG_CODEC == SWCODEC
/* parse RVA2 binary data and convert to replaygain information. */
static int parserva2( struct mp3entry* entry, char* tag, int bufferpos )
static int parserva2( struct mp3entry* entry, char* tag, int bufferpos)
{
int desc_len = strlen(tag);
int start_pos = tag - entry->id3v2buf;
int end_pos = start_pos + desc_len + 5;
int value_len = 0;
unsigned char* value = tag + desc_len + 1;
/* Only parse RVA2 replaygain tags if tag version == 2.4 and channel
@ -447,11 +440,10 @@ static int parserva2( struct mp3entry* entry, char* tag, int bufferpos )
}
}
value_len = parse_replaygain_int(album, gain, peak * 2, entry,
tag, sizeof(entry->id3v2buf) - start_pos);
parse_replaygain_int(album, gain, peak * 2, entry);
}
return start_pos + value_len;
return start_pos;
}
#endif

View file

@ -333,7 +333,7 @@ long parse_tag(const char* name, char* value, struct mp3entry* id3,
}
else
{
len = parse_replaygain(name, value, id3, buf, buf_remaining);
parse_replaygain(name, value, id3);
p = NULL;
}

View file

@ -528,13 +528,7 @@ static bool read_mp4_tags(int fd, struct mp3entry* id3,
buffer -= length;
buffer_left += length;
if (parse_replaygain(tag_name, buffer, id3,
buffer, buffer_left) > 0)
{
/* Data used, keep it. */
buffer += length;
buffer_left -= length;
}
parse_replaygain(tag_name, buffer, id3);
}
}
}

View file

@ -46,8 +46,7 @@ static int set_replaygain_sv7(struct mp3entry* id3,
/* We use a peak value of 0 to indicate a given gain type isn't used. */
if (peak != 0) {
/* Save the ReplayGain data to id3-structure for further processing. */
used += parse_replaygain_int(album, gain * 512 / 100, peak << 9,
id3, id3->toc + used, sizeof(id3->toc) - used);
parse_replaygain_int(album, gain * 512 / 100, peak << 9, id3);
}
return used;
@ -73,8 +72,7 @@ static int set_replaygain_sv8(struct mp3entry* id3,
/* We use a peak value of 0 to indicate a given gain type isn't used. */
if (peak != 0) {
/* Save the ReplayGain data to id3-structure for further processing. */
used += parse_replaygain_int(album, gain * 512 / 100, peak,
id3, id3->toc + used, sizeof(id3->toc) - used);
parse_replaygain_int(album, gain * 512 / 100, peak, id3);
}
return used;

View file

@ -36,6 +36,13 @@
#define FP_BITS (12)
#define FP_ONE (1 << FP_BITS)
void replaygain_itoa(char* buffer, int length, long int_gain)
{
/* int_gain uses Q19.12 format. */
int one = abs(int_gain) >> FP_BITS;
int cent = ((abs(int_gain) & 0x0fff) * 100 + (FP_ONE/2)) >> FP_BITS;
snprintf(buffer, length, "%d.%02d dB", (int_gain<0) ? -one : one, cent);
}
static long fp_atof(const char* s, int precision)
{
@ -109,42 +116,25 @@ static long fp_atof(const char* s, int precision)
+ (((int64_t) frac_part * int_one) / frac_max_int));
}
static long convert_gain(long gain)
long convert_gain(long gain)
{
/* Don't allow unreasonably low or high gain changes.
* Our math code can't handle it properly anyway. :)
*/
if (gain < (-48 * FP_ONE))
{
gain = -48 * FP_ONE;
}
gain = MAX(gain,-48 * FP_ONE);
gain = MIN(gain, 17 * FP_ONE);
if (gain > (17 * FP_ONE))
{
gain = 17 * FP_ONE;
}
gain = fp_factor(gain, FP_BITS) << (24 - FP_BITS);
return gain;
return fp_factor(gain, FP_BITS) << (24 - FP_BITS);
}
/* Get the sample scale factor in Q7.24 format from a gain value. Returns 0
/* Get the sample scale factor in Q19.12 format from a gain value. Returns 0
* for no gain.
*
* str Gain in dB as a string. E.g., "-3.45 dB"; the "dB" part is ignored.
*/
static long get_replaygain(const char* str)
{
long gain = 0;
if (str)
{
gain = fp_atof(str, FP_BITS);
gain = convert_gain(gain);
}
return gain;
return fp_atof(str, FP_BITS);
}
/* Get the peak volume in Q7.24 format.
@ -153,14 +143,7 @@ static long get_replaygain(const char* str)
*/
static long get_replaypeak(const char* str)
{
long peak = 0;
if (str)
{
peak = fp_atof(str, 24);
}
return peak;
return fp_atof(str, 24);
}
/* Get a sample scale factor in Q7.24 format from a gain value.
@ -174,107 +157,60 @@ long get_replaygain_int(long int_gain)
/* Parse a ReplayGain tag conforming to the "VorbisGain standard". If a
* valid tag is found, update mp3entry struct accordingly. Existing values
* are not overwritten. Returns number of bytes written to buffer.
* are not overwritten.
*
* key Name of the tag.
* value Value of the tag.
* entry mp3entry struct to update.
* buffer Where to store the text for gain values (for later display).
* length Bytes left in buffer.
*/
long parse_replaygain(const char* key, const char* value,
struct mp3entry* entry, char* buffer, int length)
void parse_replaygain(const char* key, const char* value,
struct mp3entry* entry)
{
char **p = NULL;
if (((strcasecmp(key, "replaygain_track_gain") == 0)
|| (strcasecmp(key, "rg_radio") == 0)) && !entry->track_gain)
if (((strcasecmp(key, "replaygain_track_gain") == 0) ||
(strcasecmp(key, "rg_radio") == 0)) &&
!entry->track_gain)
{
entry->track_gain = get_replaygain(value);
p = &(entry->track_gain_string);
}
else if (((strcasecmp(key, "replaygain_album_gain") == 0)
|| (strcasecmp(key, "rg_audiophile") == 0)) && !entry->album_gain)
else if (((strcasecmp(key, "replaygain_album_gain") == 0) ||
(strcasecmp(key, "rg_audiophile") == 0)) &&
!entry->album_gain)
{
entry->album_gain = get_replaygain(value);
p = &(entry->album_gain_string);
}
else if (((strcasecmp(key, "replaygain_track_peak") == 0)
|| (strcasecmp(key, "rg_peak") == 0)) && !entry->track_peak)
else if (((strcasecmp(key, "replaygain_track_peak") == 0) ||
(strcasecmp(key, "rg_peak") == 0)) &&
!entry->track_peak)
{
entry->track_peak = get_replaypeak(value);
}
else if ((strcasecmp(key, "replaygain_album_peak") == 0)
&& !entry->album_peak)
else if ((strcasecmp(key, "replaygain_album_peak") == 0) &&
!entry->album_peak)
{
entry->album_peak = get_replaypeak(value);
}
if (p)
{
int len = strlen(value);
len = MIN(len, length - 1);
/* A few characters just isn't interesting... */
if (len > 1)
{
strlcpy(buffer, value, len + 1);
*p = buffer;
return len + 1;
}
}
return 0;
}
/* Set ReplayGain values from integers. Existing values are not overwritten.
* Returns number of bytes written to buffer.
*
* album If true, set album values, otherwise set track values.
* gain Gain value in dB, multiplied by 512. 0 for no gain.
* peak Peak volume in Q7.24 format, where 1.0 is full scale. 0 for no
* peak volume.
* buffer Where to store the text for gain values (for later display).
* length Bytes left in buffer.
*/
long parse_replaygain_int(bool album, long gain, long peak,
struct mp3entry* entry, char* buffer, int length)
void parse_replaygain_int(bool album, long gain, long peak,
struct mp3entry* entry)
{
long len = 0;
if (buffer != NULL)
{
len = snprintf(buffer, length, "%ld.%02d dB", gain / 512,
((abs(gain) & 0x01ff) * 100 + 256) / 512);
len++;
}
if (gain != 0)
{
gain = convert_gain(gain * FP_ONE / 512);
}
gain = gain * FP_ONE / 512;
if (album)
{
entry->album_gain = gain;
entry->album_gain_string = buffer;
if (peak)
{
entry->album_peak = peak;
}
}
else
{
entry->track_gain = gain;
entry->track_gain_string = buffer;
if (peak)
{
entry->track_peak = peak;
}
}
return len;
}

View file

@ -25,9 +25,11 @@
#include "metadata.h"
long get_replaygain_int(long int_gain);
long parse_replaygain(const char* key, const char* value,
struct mp3entry* entry, char* buffer, int length);
long parse_replaygain_int(bool album, long gain, long peak,
struct mp3entry* entry, char* buffer, int length);
void parse_replaygain(const char* key, const char* value,
struct mp3entry* entry);
void parse_replaygain_int(bool album, long gain, long peak,
struct mp3entry* entry);
void replaygain_itoa(char* buffer, int length, long int_gain);
long convert_gain(long gain);
#endif

View file

@ -53,6 +53,7 @@
#include "backdrop.h"
#include "viewport.h"
#include "language.h"
#include "replaygain.h"
#if CONFIG_CODEC == SWCODEC
#include "dsp.h"
@ -728,10 +729,12 @@ static const char* id3_get_info(int selected_item, void* data,
break;
#if CONFIG_CODEC == SWCODEC
case LANG_ID3_TRACK_GAIN:
val=id3->track_gain_string;
replaygain_itoa(buffer, buffer_len, id3->track_gain);
val=(id3->track_gain) ? buffer : NULL; /* only show gains!=0 */
break;
case LANG_ID3_ALBUM_GAIN:
val=id3->album_gain_string;
replaygain_itoa(buffer, buffer_len, id3->album_gain);
val=(id3->album_gain) ? buffer : NULL; /* only show gains!=0 */
break;
#endif
case LANG_ID3_PATH: