More details about the profile (main type of encoder settings).
---
Doc/cmus.txt | 8 +++++---
aac.c | 32 +++++++++++++++++++++++++++++++-
cache.c | 16 +++++++++++-----
expr.c | 3 +++
ffmpeg.c | 30 +++++++++++++++++++++++++++++-
flac.c | 9 ++++++++-
input.c | 12 ++++++++++++
input.h | 1 +
ip.h | 1 +
mad.c | 34 ++++++++++++++++++++++++++++++++--
mikmod.c | 8 +++++++-
modplug.c | 8 +++++++-
mp4.c | 31 ++++++++++++++++++++++++++++++-
mpc.c | 23 ++++++++++++++++++++++-
nomad.c | 40 +++++++++++++++++++++-------------------
nomad.h | 18 ++++++++++++++++++
options.c | 1 +
track_info.c | 2 ++
track_info.h | 2 ++
ui_curses.c | 3 +++
vorbis.c | 39 ++++++++++++++++++++++++++++++++++++++-
wav.c | 8 +++++++-
wavpack.c | 32 +++++++++++++++++++++++++++++++-
23 files changed, 322 insertions(+), 39 deletions(-)
diff --git a/Doc/cmus.txt b/Doc/cmus.txt
index 4ec3c07..af66b2c 100644
--- a/Doc/cmus.txt
+++ b/Doc/cmus.txt
@@ -957,6 +957,7 @@ Special Keys:
%F %{filename} @br
%{bitrate} @br
%{codec} @br
+ %{codec_profile} @br
%{rg_track_gain} @br
%{rg_track_peak} @br
%{rg_album_gain} @br
@@ -986,8 +987,8 @@ Sort option (lib_sort, pl_sort) value is space separated list of the following
sort keys:
artist, album, title, tracknumber, discnumber, date, genre, comment,
- albumartist, filename, filemtime, bitrate, codec, rg_track_gain,
- rg_track_peak, rg_album_gain, rg_album_peak
+ albumartist, filename, filemtime, bitrate, codec, codec_profile,
+ rg_track_gain, rg_track_peak, rg_album_gain, rg_album_peak
@h1 PLUGIN OPTIONS
@@ -1092,7 +1093,8 @@ built-in filters. Also (and)-grouping is done implicitly.
@h2 Strings
@li long
-*filename*, *artist*, *album*, *title*, *genre*, *comment*, *codec*
+*filename*, *artist*, *album*, *title*, *genre*, *comment*, *codec*,
+*codec_profile*
@br
Comparators: *=* and *!=* (not equal)
diff --git a/aac.c b/aac.c
index ef991c9..3153fae 100644
--- a/aac.c
+++ b/aac.c
@@ -26,6 +26,7 @@
#include <neaacdec.h>
+#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
@@ -43,6 +44,7 @@ struct aac_private {
unsigned char channels;
unsigned long sample_rate;
long bitrate;
+ int object_type;
char *overflow_buf;
int overflow_buf_len;
@@ -195,6 +197,7 @@ static int aac_open(struct input_plugin_data *ip_data)
priv = xnew0(struct aac_private, 1);
priv->decoder = NeAACDecOpen();
priv->bitrate = -1;
+ priv->object_type = -1;
ip_data->private = priv;
/* set decoder config */
@@ -429,6 +432,8 @@ static int aac_duration(struct input_plugin_data *ip_data)
/* 8 * file_size / duration */
priv->bitrate = (8 * bytes * priv->sample_rate) / samples;
+ priv->object_type = frame_info.object_type;
+
return ((file_size / bytes) * samples) / priv->sample_rate;
}
@@ -443,6 +448,30 @@ static char *aac_codec(struct input_plugin_data *ip_data)
return xstrdup("aac");
}
+static const char *object_type_to_str(int object_type)
+{
+ switch (object_type) {
+ case MAIN: return "Main";
+ case LC: return "LC";
+ case SSR: return "SSR";
+ case LTP: return "LTP";
+ case HE_AAC: return "HE";
+ case ER_LC: return "ER-LD";
+ case ER_LTP: return "ER-LTP";
+ case LD: return "LD";
+ case DRM_ER_LC: return "DRM-ER-LC";
+ }
+ return NULL;
+}
+
+static char *aac_codec_profile(struct input_plugin_data *ip_data)
+{
+ struct aac_private *priv = ip_data->private;
+ const char *profile = object_type_to_str(priv->object_type);
+
+ return profile ? xstrdup(profile) : NULL;
+}
+
const struct input_plugin_ops ip_ops = {
.open = aac_open,
.close = aac_close,
@@ -451,7 +480,8 @@ const struct input_plugin_ops ip_ops = {
.read_comments = aac_read_comments,
.duration = aac_duration,
.bitrate = aac_bitrate,
- .codec = aac_codec
+ .codec = aac_codec,
+ .codec_profile = aac_codec_profile
};
const int ip_priority = 50;
diff --git a/cache.c b/cache.c
index 48f91c8..710122c 100644
--- a/cache.c
+++ b/cache.c
@@ -32,7 +32,7 @@ struct cache_entry {
long bitrate;
time_t mtime;
- // filename, codec and N * (key, val)
+ // filename, codec, codec_profile and N * (key, val)
char strings[];
};
@@ -85,7 +85,7 @@ static int valid_cache_entry(const struct cache_entry *e, unsigned int avail)
if (!e->strings[i])
count++;
}
- if (count % 2 == 1)
+ if (count % 2 == 0)
return 0;
if (e->strings[str_size - 1])
return 0;
@@ -104,18 +104,20 @@ static struct track_info *cache_entry_to_ti(struct cache_entry *e)
ti->bitrate = e->bitrate;
ti->mtime = e->mtime;
- // count strings (filename + codec + key/val pairs)
+ // count strings (filename + codec + codec_profile + key/val pairs)
count = 0;
for (i = 0; i < str_size; i++) {
if (!strings[i])
count++;
}
- count = (count - 2) / 2;
+ count = (count - 3) / 2;
// NOTE: filename already copied by track_info_new()
pos = strlen(strings) + 1;
ti->codec = strings[pos] ? xstrdup(strings + pos) : NULL;
pos += strlen(strings + pos) + 1;
+ ti->codec_profile = strings[pos] ? xstrdup(strings + pos) : NULL;
+ pos += strlen(strings + pos) + 1;
kv = xnew(struct keyval, count + 1);
for (i = 0; i < count; i++) {
int size;
@@ -241,7 +243,7 @@ int cache_init(void)
cache_header[4] = flags & 0xff;
/* assumed version */
- cache_header[3] = 0x05;
+ cache_header[3] = 0x06;
cache_filename = xstrjoin(cmus_config_dir, "/cache");
return read_cache();
@@ -300,6 +302,8 @@ static void write_ti(int fd, struct gbuf *buf, struct track_info *ti, unsigned i
e.size += len[count++];
len[count] = (ti->codec ? strlen(ti->codec) : 0) + 1;
e.size += len[count++];
+ len[count] = (ti->codec_profile ? strlen(ti->codec_profile) : 0) + 1;
+ e.size += len[count++];
for (i = 0; kv[i].key; i++) {
if (count + 2 > alloc) {
alloc *= 2;
@@ -321,6 +325,7 @@ static void write_ti(int fd, struct gbuf *buf, struct track_info *ti, unsigned i
gbuf_add_bytes(buf, &e, sizeof(e));
gbuf_add_bytes(buf, ti->filename, len[count++]);
gbuf_add_bytes(buf, ti->codec ? ti->codec : "", len[count++]);
+ gbuf_add_bytes(buf, ti->codec_profile ? ti->codec_profile : "", len[count++]);
for (i = 0; kv[i].key; i++) {
gbuf_add_bytes(buf, kv[i].key, len[count++]);
gbuf_add_bytes(buf, kv[i].val, len[count++]);
@@ -383,6 +388,7 @@ static struct track_info *ip_get_ti(const char *filename)
ti->duration = ip_duration(ip);
ti->bitrate = ip_bitrate(ip);
ti->codec = ip_codec(ip);
+ ti->codec_profile = ip_codec_profile(ip);
ti->mtime = ip_is_remote(ip) ? -1 : file_get_mtime(filename);
}
ip_delete(ip);
diff --git a/expr.c b/expr.c
index 559b1ab..95e5111 100644
--- a/expr.c
+++ b/expr.c
@@ -411,6 +411,7 @@ static const struct {
{ "artist", EXPR_STR },
{ "bitrate", EXPR_INT },
{ "codec", EXPR_STR },
+ { "codec_profile",EXPR_STR },
{ "comment", EXPR_STR },
{ "date", EXPR_INT },
{ "discnumber", EXPR_INT },
@@ -877,6 +878,8 @@ int expr_eval(struct expr *expr, struct track_info *ti)
val = uval;
} else if (strcmp(key, "codec") == 0) {
val = ti->codec;
+ } else if (strcmp(key, "codec_profile") == 0) {
+ val = ti->codec_profile;
} else {
val = keyvals_get_val(ti->comments, key);
}
diff --git a/ffmpeg.c b/ffmpeg.c
index b5b9932..4b45364 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -457,6 +457,33 @@ static char *ffmpeg_codec(struct input_plugin_data *ip_data)
return xstrdup(priv->codec->name);
}
+#if (LIBAVCODEC_VERSION_INT < ((52<<16)+(104<<8)+0))
+static const char *codec_profile_to_str(int profile)
+{
+ switch (profile) {
+ case FF_PROFILE_AAC_MAIN: return "Main";
+ case FF_PROFILE_AAC_LOW: return "LC";
+ case FF_PROFILE_AAC_SSR: return "SSR";
+ case FF_PROFILE_AAC_LTP: return "LTP";
+ }
+ return NULL;
+}
+#endif
+
+static char *ffmpeg_codec_profile(struct input_plugin_data *ip_data)
+{
+ struct ffmpeg_private *priv = ip_data->private;
+ const char *profile;
+
+#if (LIBAVCODEC_VERSION_INT < ((52<<16)+(104<<8)+0))
+ profile = codec_profile_to_str(priv->codec_context->profile);
+#else
+ profile = av_get_profile_name(priv->codec, priv->codec_context->profile);
+#endif
+
+ return profile ? xstrdup(profile) : NULL;
+}
+
const struct input_plugin_ops ip_ops = {
.open = ffmpeg_open,
.close = ffmpeg_close,
@@ -465,7 +492,8 @@ const struct input_plugin_ops ip_ops = {
.read_comments = ffmpeg_read_comments,
.duration = ffmpeg_duration,
.bitrate = ffmpeg_bitrate,
- .codec = ffmpeg_codec
+ .codec = ffmpeg_codec,
+ .codec_profile = ffmpeg_codec_profile
};
const int ip_priority = 30;
diff --git a/flac.c b/flac.c
index 41cae40..6e3a2a4 100644
--- a/flac.c
+++ b/flac.c
@@ -532,6 +532,12 @@ static char *flac_codec(struct input_plugin_data *ip_data)
return xstrdup("flac");
}
+static char *flac_codec_profile(struct input_plugin_data *ip_data)
+{
+ /* maybe identify compression-level over min/max blocksize/framesize */
+ return NULL;
+}
+
const struct input_plugin_ops ip_ops = {
.open = flac_open,
.close = flac_close,
@@ -540,7 +546,8 @@ const struct input_plugin_ops ip_ops = {
.read_comments = flac_read_comments,
.duration = flac_duration,
.bitrate = flac_bitrate,
- .codec = flac_codec
+ .codec = flac_codec,
+ .codec_profile = flac_codec_profile
};
const int ip_priority = 50;
diff --git a/input.c b/input.c
index 223a5ee..651ca7a 100644
--- a/input.c
+++ b/input.c
@@ -60,6 +60,8 @@ struct input_plugin {
long bitrate;
/* cached codec, NULL = unset */
char *codec;
+ /* cached codec_profile, NULL = unset */
+ char *codec_profile;
/*
* pcm is converted to 16-bit signed little-endian stereo
@@ -383,6 +385,7 @@ static void ip_init(struct input_plugin *ip, char *filename)
ip->duration = -1;
ip->bitrate = -1;
ip->codec = NULL;
+ ip->codec_profile = NULL;
ip->data.fd = -1;
ip->data.filename = filename;
ip->data.remote = is_url(filename);
@@ -723,6 +726,15 @@ char *ip_codec(struct input_plugin *ip)
return ip->codec;
}
+char *ip_codec_profile(struct input_plugin *ip)
+{
+ if (ip->data.remote)
+ return NULL;
+ if (!ip->codec_profile)
+ ip->codec_profile = ip->ops->codec_profile(&ip->data);
+ return ip->codec_profile;
+}
+
sample_format_t ip_get_sf(struct input_plugin *ip)
{
BUG_ON(!ip->open);
diff --git a/input.h b/input.h
index 1f08f84..489456a 100644
--- a/input.h
+++ b/input.h
@@ -53,6 +53,7 @@ int ip_read_comments(struct input_plugin *ip, struct keyval **comments);
int ip_duration(struct input_plugin *ip);
int ip_bitrate(struct input_plugin *ip);
char *ip_codec(struct input_plugin *ip);
+char *ip_codec_profile(struct input_plugin *ip);
sample_format_t ip_get_sf(struct input_plugin *ip);
const char *ip_get_filename(struct input_plugin *ip);
diff --git a/ip.h b/ip.h
index acaa8b9..c0409b4 100644
--- a/ip.h
+++ b/ip.h
@@ -86,6 +86,7 @@ struct input_plugin_ops {
int (*duration)(struct input_plugin_data *ip_data);
long (*bitrate)(struct input_plugin_data *ip_data);
char *(*codec)(struct input_plugin_data *ip_data);
+ char *(*codec_profile)(struct input_plugin_data *ip_data);
};
/* symbols exported by plugin */
diff --git a/mad.c b/mad.c
index 4ec6891..779af11 100644
--- a/mad.c
+++ b/mad.c
@@ -24,6 +24,7 @@
#include "xmalloc.h"
#include "read_wrapper.h"
#include "debug.h"
+#include "utils.h"
#include <stdio.h>
#include <math.h>
@@ -172,7 +173,7 @@ out:
ape_free(&ape);
/* add last so the other tags get preference */
- if (!isnan(lame->trackGain)) {
+ if (lame && !isnan(lame->trackGain)) {
char buf[64];
if (!isnan(lame->peak)) {
@@ -218,6 +219,34 @@ static char *mad_codec(struct input_plugin_data *ip_data)
return NULL;
}
+static char *mad_codec_profile(struct input_plugin_data *ip_data)
+{
+ struct nomad *nomad = ip_data->private;
+ const struct nomad_lame *lame = nomad_lame(nomad);
+ const struct nomad_xing *xing = nomad_xing(nomad);
+ const char *mode = nomad_info(nomad)->vbr ? "vbr" : "cbr";
+
+ if (xing && lame) {
+ const char const * vbr_map[] = { NULL, "cbr", "abr", "vbr-old", "vbr", "vbr-mt" };
+
+ if (lame->vbr_method && lame->vbr_method < N_ELEMENTS(vbr_map)) {
+ mode = vbr_map[lame->vbr_method];
+
+ if (xing->flags & XING_SCALE && xing->scale && xing->scale <= 100) {
+ char buf[32];
+ int v = 10 - (xing->scale + 9) / 10;
+ int q = 10 - (xing->scale - ((9 - v) * 10));
+
+ sprintf(buf, "%s V%d q%d", mode, v, q);
+ return xstrdup(buf);
+
+ }
+ }
+ }
+
+ return xstrdup(mode);
+}
+
const struct input_plugin_ops ip_ops = {
.open = mad_open,
.close = mad_close,
@@ -226,7 +255,8 @@ const struct input_plugin_ops ip_ops = {
.read_comments = mad_read_comments,
.duration = mad_duration,
.bitrate = mad_bitrate,
- .codec = mad_codec
+ .codec = mad_codec,
+ .codec_profile = mad_codec_profile
};
const int ip_priority = 55;
diff --git a/mikmod.c b/mikmod.c
index 658b259..2021f61 100644
--- a/mikmod.c
+++ b/mikmod.c
@@ -149,6 +149,11 @@ static char *mik_codec(struct input_plugin_data *ip_data)
return (codec && codec[0]) ? xstrdup(codec) : NULL;
}
+static char *mik_codec_profile(struct input_plugin_data *ip_data)
+{
+ return NULL;
+}
+
const struct input_plugin_ops ip_ops = {
.open = mik_open,
.close = mik_close,
@@ -157,7 +162,8 @@ const struct input_plugin_ops ip_ops = {
.read_comments = mik_read_comments,
.duration = mik_duration,
.bitrate = mik_bitrate,
- .codec = mik_codec
+ .codec = mik_codec,
+ .codec_profile = mik_codec_profile
};
const int ip_priority = 40;
diff --git a/modplug.c b/modplug.c
index b1df3aa..981f5b3 100644
--- a/modplug.c
+++ b/modplug.c
@@ -201,6 +201,11 @@ static char *mod_codec(struct input_plugin_data *ip_data)
return codec ? xstrdup(codec) : NULL;
}
+static char *mod_codec_profile(struct input_plugin_data *ip_data)
+{
+ return NULL;
+}
+
const struct input_plugin_ops ip_ops = {
.open = mod_open,
.close = mod_close,
@@ -209,7 +214,8 @@ const struct input_plugin_ops ip_ops = {
.read_comments = mod_read_comments,
.duration = mod_duration,
.bitrate = mod_bitrate,
- .codec = mod_codec
+ .codec = mod_codec,
+ .codec_profile = mod_codec_profile
};
const int ip_priority = 50;
diff --git a/mp4.c b/mp4.c
index 5149358..ac4fdfb 100644
--- a/mp4.c
+++ b/mp4.c
@@ -474,6 +474,34 @@ static char *mp4_codec(struct input_plugin_data *ip_data)
return xstrdup("aac");
}
+static const char *object_type_to_str(uint8_t obj_type)
+{
+ switch (obj_type) {
+ case MP4_MPEG4_AAC_MAIN_AUDIO_TYPE: return "Main";
+ case MP4_MPEG4_AAC_LC_AUDIO_TYPE: return "LC";
+ case MP4_MPEG4_AAC_SSR_AUDIO_TYPE: return "SSR";
+ case MP4_MPEG4_AAC_LTP_AUDIO_TYPE: return "LTP";
+ case MP4_MPEG4_AAC_HE_AUDIO_TYPE: return "HE";
+ case MP4_MPEG4_AAC_SCALABLE_AUDIO_TYPE: return "Scalable";
+ }
+ return NULL;
+}
+
+static char *mp4_codec_profile(struct input_plugin_data *ip_data)
+{
+ struct mp4_private *priv = ip_data->private;
+ const char *profile;
+ uint8_t obj_type;
+
+ obj_type = MP4GetTrackEsdsObjectTypeId(priv->mp4.handle, priv->mp4.track);
+ if (obj_type == MP4_MPEG4_AUDIO_TYPE)
+ obj_type = MP4GetTrackAudioMpeg4Type(priv->mp4.handle, priv->mp4.track);
+
+ profile = object_type_to_str(obj_type);
+
+ return profile ? xstrdup(profile) : NULL;
+}
+
const struct input_plugin_ops ip_ops = {
.open = mp4_open,
.close = mp4_close,
@@ -482,7 +510,8 @@ const struct input_plugin_ops ip_ops = {
.read_comments = mp4_read_comments,
.duration = mp4_duration,
.bitrate = mp4_bitrate,
- .codec = mp4_codec
+ .codec = mp4_codec,
+ .codec_profile = mp4_codec_profile
};
const int ip_priority = 50;
diff --git a/mpc.c b/mpc.c
index 05990e4..6006499 100644
--- a/mpc.c
+++ b/mpc.c
@@ -378,6 +378,26 @@ static char *mpc_codec(struct input_plugin_data *ip_data)
return NULL;
}
+static char *mpc_codec_profile(struct input_plugin_data *ip_data)
+{
+ struct mpc_private *priv = ip_data->private;
+ const char *profile = priv->info.profile_name;
+ char *s = NULL;
+
+ if (profile && profile[0]) {
+ int i;
+
+ /* remove single quotes */
+ while (*profile == '\'')
+ profile++;
+ s = xstrdup(profile);
+ for (i = strlen(s) - 1; s[i] == '\'' && i >= 0; i--)
+ s[i] = '\0';
+ }
+
+ return s;
+}
+
const struct input_plugin_ops ip_ops = {
.open = mpc_open,
.close = mpc_close,
@@ -386,7 +406,8 @@ const struct input_plugin_ops ip_ops = {
.read_comments = mpc_read_comments,
.duration = mpc_duration,
.bitrate = mpc_bitrate,
- .codec = mpc_codec
+ .codec = mpc_codec,
+ .codec_profile = mpc_codec_profile
};
const int ip_priority = 50;
diff --git a/nomad.c b/nomad.c
index 89f6b23..ce9ddd3 100644
--- a/nomad.c
+++ b/nomad.c
@@ -71,15 +71,7 @@ struct nomad {
int end_drop_samples;
int end_drop_frames;
- struct {
- unsigned int is_info : 1;
- unsigned int flags;
- unsigned int nr_frames;
- unsigned int bytes;
- unsigned int scale;
- unsigned char toc[100];
- } xing;
-
+ struct nomad_xing xing;
struct nomad_lame lame;
struct {
@@ -137,9 +129,16 @@ static int parse_lame(struct nomad *nomad, struct mad_bitptr ptr, int bitlen)
d_print("detected LAME version %s\n", nomad->lame.encoder + 4);
#endif
+ i = mad_bit_read(&ptr, 4);
+#if defined(DEBUG_LAME)
+ d_print("LAME tag revision: %d\n", i);
+#endif
+ nomad->lame.vbr_method = mad_bit_read(&ptr, 4);
+
/* ReplayGain in LAME tag was added in 3.94 */
if (version_major > 3 || (version_major == 3 && version_minor >= 94)) {
- mad_bit_read(&ptr, 16);
+ /* lowpass */
+ mad_bit_read(&ptr, 8);
/* The reference volume was changed from the 83dB used in the
* ReplayGain spec to 89dB in lame 3.95.1. Bump the gain for older
@@ -168,9 +167,14 @@ static int parse_lame(struct nomad *nomad, struct mad_bitptr ptr, int bitlen)
*/
}
+ /*
+ * 4 encoding flags
+ * 4 ATH type
+ * 8 minimal bitrate (if ABR -> specified bitrate)
+ */
mad_bit_read(&ptr, 16);
} else
- mad_bit_read(&ptr, 96);
+ mad_bit_read(&ptr, 88);
nomad->lame.encoderDelay = mad_bit_read(&ptr, 12);
nomad->lame.encoderPadding = mad_bit_read(&ptr, 12);
@@ -199,13 +203,6 @@ static int parse_lame(struct nomad *nomad, struct mad_bitptr ptr, int bitlen)
return 1;
}
-enum {
- XING_FRAMES = 0x00000001L,
- XING_BYTES = 0x00000002L,
- XING_TOC = 0x00000004L,
- XING_SCALE = 0x00000008L
-};
-
/*
* format:
*
@@ -831,9 +828,14 @@ int nomad_time_seek(struct nomad *nomad, double pos)
return 0;
}
+const struct nomad_xing *nomad_xing(struct nomad *nomad)
+{
+ return nomad->has_xing ? &nomad->xing : NULL;
+}
+
const struct nomad_lame *nomad_lame(struct nomad *nomad)
{
- return &nomad->lame;
+ return nomad->has_lame ? &nomad->lame : NULL;
}
const struct nomad_info *nomad_info(struct nomad *nomad)
diff --git a/nomad.h b/nomad.h
index 52602a6..403a8a1 100644
--- a/nomad.h
+++ b/nomad.h
@@ -33,8 +33,25 @@ struct nomad_callbacks {
int (*close)(void *datasource);
};
+enum {
+ XING_FRAMES = 0x00000001L,
+ XING_BYTES = 0x00000002L,
+ XING_TOC = 0x00000004L,
+ XING_SCALE = 0x00000008L
+};
+
+struct nomad_xing {
+ unsigned int is_info : 1;
+ unsigned int flags;
+ unsigned int nr_frames;
+ unsigned int bytes;
+ unsigned int scale;
+ unsigned char toc[100];
+};
+
struct nomad_lame {
char encoder[10]; /* 9 byte encoder name/version ("LAME3.97b") */
+ int vbr_method; /* VBR method */
float peak; /* replaygain peak */
float trackGain; /* replaygain track gain */
float albumGain; /* replaygain album gain */
@@ -79,6 +96,7 @@ int nomad_read(struct nomad *nomad, char *buffer, int count);
/* -NOMAD_ERROR_ERRNO */
int nomad_time_seek(struct nomad *nomad, double pos);
+const struct nomad_xing *nomad_xing(struct nomad *nomad);
const struct nomad_lame *nomad_lame(struct nomad *nomad);
const struct nomad_info *nomad_info(struct nomad *nomad);
diff --git a/options.c b/options.c
index df81d9e..5c37bbd 100644
--- a/options.c
+++ b/options.c
@@ -210,6 +210,7 @@ static const struct {
{ "rg_album_peak", SORT_RG_ALBUM_PEAK },
{ "bitrate", SORT_BITRATE },
{ "codec", SORT_CODEC },
+ { "codec_profile", SORT_CODEC_PROFILE },
{ NULL, SORT_INVALID }
};
diff --git a/track_info.c b/track_info.c
index 0859c24..2e5c258 100644
--- a/track_info.c
+++ b/track_info.c
@@ -34,6 +34,7 @@ static void track_info_free(struct track_info *ti)
keyvals_free(ti->comments);
free(ti->filename);
free(ti->codec);
+ free(ti->codec_profile);
free(ti->collkey_artist);
free(ti->collkey_album);
free(ti->collkey_title);
@@ -51,6 +52,7 @@ struct track_info *track_info_new(const char *filename)
ti->ref = 1;
ti->comments = NULL;
ti->codec = NULL;
+ ti->codec_profile = NULL;
return ti;
}
diff --git a/track_info.h b/track_info.h
index 15a3db7..831ae3a 100644
--- a/track_info.h
+++ b/track_info.h
@@ -33,6 +33,7 @@ struct track_info {
int duration;
long bitrate;
char *codec;
+ char *codec_profile;
int ref;
char *filename;
@@ -80,6 +81,7 @@ typedef size_t sort_key_t;
#define SORT_FILEMTIME offsetof(struct track_info, mtime)
#define SORT_BITRATE offsetof(struct track_info, bitrate)
#define SORT_CODEC offsetof(struct track_info, codec)
+#define SORT_CODEC_PROFILE offsetof(struct track_info, codec_profile)
#define SORT_INVALID ((sort_key_t) (-1))
#define TI_MATCH_ARTIST (1 << 0)
diff --git a/ui_curses.c b/ui_curses.c
index 60f33bc..5a3bf07 100644
--- a/ui_curses.c
+++ b/ui_curses.c
@@ -222,6 +222,7 @@ enum {
TF_DURATION,
TF_BITRATE,
TF_CODEC,
+ TF_CODEC_PROFILE,
TF_PATHFILE,
TF_FILE,
TF_RG_TRACK_GAIN,
@@ -244,6 +245,7 @@ static struct format_option track_fopts[NR_TFS + 1] = {
DEF_FO_TIME('d', "duration", 0),
DEF_FO_INT('\0', "bitrate", 0),
DEF_FO_STR('\0', "codec", 0),
+ DEF_FO_STR('\0', "codec_profile", 0),
DEF_FO_STR('f', "path", 0),
DEF_FO_STR('F', "filename", 0),
DEF_FO_DOUBLE('\0', "rg_track_gain", 0),
@@ -558,6 +560,7 @@ static void fill_track_fopts_track_info(struct track_info *info)
fopt_set_double(&track_fopts[TF_RG_ALBUM_PEAK], info->rg_album_peak, isnan(info->rg_album_peak));
fopt_set_int(&track_fopts[TF_BITRATE], (int) (info->bitrate / 1000. + 0.5), info->bitrate == -1);
fopt_set_str(&track_fopts[TF_CODEC], info->codec);
+ fopt_set_str(&track_fopts[TF_CODEC_PROFILE], info->codec_profile);
fopt_set_str(&track_fopts[TF_PATHFILE], filename);
if (is_url(info->filename)) {
fopt_set_str(&track_fopts[TF_FILE], filename);
diff --git a/vorbis.c b/vorbis.c
index 87dded6..dda41ae 100644
--- a/vorbis.c
+++ b/vorbis.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
+#include <math.h>
struct vorbis_private {
OggVorbis_File vf;
@@ -305,6 +306,41 @@ static char *vorbis_codec(struct input_plugin_data *ip_data)
return xstrdup("vorbis");
}
+static const long rate_mapping_44[2][12] = {
+ { 32000, 48000, 60000, 70000, 80000, 86000, 96000, 110000, 120000, 140000, 160000, 239920 },
+ { 45000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 499821 }
+};
+
+static char *vorbis_codec_profile(struct input_plugin_data *ip_data)
+{
+ struct vorbis_private *priv = ip_data->private;
+ vorbis_info *vi = ov_info(&priv->vf, -1);
+ long b = vi->bitrate_nominal;
+ char buf[64];
+
+ if (b <= 0)
+ return NULL;
+
+ if (vi->channels > 2 || vi->rate < 44100) {
+ sprintf(buf, "b%ldk", b / 1000);
+ } else {
+ const long *map = rate_mapping_44[vi->channels - 1];
+ float q;
+ int i;
+
+ for (i = 0; i < 12-1; i++) {
+ if (b >= map[i] && b < map[i+1])
+ break;
+ }
+ /* This is used even if upper / lower bitrate are set
+ * because it gives a good approximation. */
+ q = (i - 1) + (float) (b - map[i]) / (map[i+1] - map[i]);
+ sprintf(buf, "q%g", roundf(q * 100.f) / 100.f);
+ }
+
+ return xstrdup(buf);
+}
+
const struct input_plugin_ops ip_ops = {
.open = vorbis_open,
.close = vorbis_close,
@@ -313,7 +349,8 @@ const struct input_plugin_ops ip_ops = {
.read_comments = vorbis_read_comments,
.duration = vorbis_duration,
.bitrate = vorbis_bitrate,
- .codec = vorbis_codec
+ .codec = vorbis_codec,
+ .codec_profile = vorbis_codec_profile
};
const int ip_priority = 50;
diff --git a/wav.c b/wav.c
index b20c9c6..18f064c 100644
--- a/wav.c
+++ b/wav.c
@@ -390,6 +390,11 @@ static char *wav_codec(struct input_plugin_data *ip_data)
return xstrdup(buf);
}
+static char *wav_codec_profile(struct input_plugin_data *ip_data)
+{
+ return NULL;
+}
+
const struct input_plugin_ops ip_ops = {
.open = wav_open,
.close = wav_close,
@@ -398,7 +403,8 @@ const struct input_plugin_ops ip_ops = {
.read_comments = wav_read_comments,
.duration = wav_duration,
.bitrate = wav_bitrate,
- .codec = wav_codec
+ .codec = wav_codec,
+ .codec_profile = wav_codec_profile
};
const int ip_priority = 50;
diff --git a/wavpack.c b/wavpack.c
index b5631a1..99a26c5 100644
--- a/wavpack.c
+++ b/wavpack.c
@@ -362,6 +362,35 @@ static char *wavpack_codec(struct input_plugin_data *ip_data)
return xstrdup("wavpack");
}
+static char *wavpack_codec_profile(struct input_plugin_data *ip_data)
+{
+ struct wavpack_private *priv = ip_data->private;
+ int m = WavpackGetMode(priv->wpc);
+ char buf[32];
+
+ buf[0] = '\0';
+
+ if (m & MODE_FAST)
+ strcat(buf, "fast");
+ else if (m & MODE_VERY_HIGH)
+ strcat(buf, "very high");
+ else if (m & MODE_HIGH)
+ strcat(buf, "high");
+ else
+ strcat(buf, "normal");
+
+ if (m & MODE_HYBRID)
+ strcat(buf, " hybrid");
+
+ if ((m & MODE_EXTRA) && (m & MODE_XMODE)) {
+ char xmode[] = " x0";
+ xmode[2] = ((m & MODE_XMODE) >> 12) + '0';
+ strcat(buf, xmode);
+ }
+
+ return xstrdup(buf);
+}
+
const struct input_plugin_ops ip_ops = {
.open = wavpack_open,
.close = wavpack_close,
@@ -370,7 +399,8 @@ const struct input_plugin_ops ip_ops = {
.read_comments = wavpack_read_comments,
.duration = wavpack_duration,
.bitrate = wavpack_bitrate,
- .codec = wavpack_codec
+ .codec = wavpack_codec,
+ .codec_profile = wavpack_codec_profile
};
const int ip_priority = 50;
--
1.7.4.1