Discussion:
ALSA - separate sound level for cmus
Róbert Kohányi
2011-02-20 08:35:27 UTC
Permalink
Hi,

I'v read through this:
http://sourceforge.net/mailarchive/message.php?msg_id=24833816 thread as
this almost describe my question.

I'm using Debian Squeze (amd64) with ALSA, no Pulseaudio and cmus (v2.3.3)
Gregory Petrosyan
2011-02-20 09:01:56 UTC
Permalink
On Sun, Feb 20, 2011 at 11:35 AM, Róbert Kohányi
Post by Róbert Kohányi
Hi,
http://sourceforge.net/mailarchive/message.php?msg_id=24833816 thread as
this almost describe my question.
I'm using Debian Squeze (amd64) with ALSA, no Pulseaudio and cmus (v2.3.3)
is controlling my PCM levels.
Róbert Kohányi
2011-02-20 09:28:11 UTC
Permalink
:set softvol=true is just perfect! Thanks for the help!

Kohányi Róbert


On Sun, Feb 20, 2011 at 10:01 AM, Gregory Petrosyan <
On Sun, Feb 20, 2011 at 11:35 AM, Róbert Kohányi
Post by Róbert Kohányi
Hi,
http://sourceforge.net/mailarchive/message.php?msg_id=24833816 thread as
this almost describe my question.
I'm using Debian Squeze (amd64) with ALSA, no Pulseaudio and cmus
(v2.3.3)
Justin Richard
2011-02-24 22:00:36 UTC
Permalink
Post by Róbert Kohányi
:set softvol=true is just perfect! Thanks for the help!
Kohányi Róbert
On Sun, Feb 20, 2011 at 10:01 AM, Gregory Petrosyan
Post by Gregory Petrosyan
On Sun, Feb 20, 2011 at 11:35 AM, Róbert Kohányi
Post by Róbert Kohányi
Hi,
http://sourceforge.net/mailarchive/message.php?msg_id=24833816 thread as
this almost describe my question.
I'm using Debian Squeze (amd64) with ALSA, no Pulseaudio and cmus (v2.3.3)
is controlling my PCM levels.
Andy Cobaugh
2011-02-24 22:26:31 UTC
Permalink
Have you considered switching to OSS4 ? At least on RPM-based distros, you
install it, reboot, and sound works perfectly. No tweaking, no messing
with config files, no playing with userspace mixers. You get
per-application volume controls, simplified configuration, and what I
think is a better sounding audio subsystem (totally subjective, but on
several machines, I honestly think OSS4 sounds better than stock ALSA).

Per-app volume sliders: Loading Image...

Just something to consider, not trying to start an oss vs alsa war.

--andy
Gregory Petrosyan
2011-02-25 23:50:54 UTC
Permalink
Oddly softvol=true does not seem to work for FLAC playback. When a
FLAC file is played it is played at current PCM volume and ignores the
softvol option. As a hack around this I tried something completely
different from ALSA, but couldn't get it to work either.
This is probably because your FLAC files have sample format different from the
one cmus knows how to scale in software.

Does anybody know a library for scaling the samples in different formats? If
it exists, we may try to integrate it into cmus. Otherwise, the only option is
to create such a library specifically for cmus. AFAIK mplayer supports
softvol, but I haven't looked at its source yet.

Gregory
Justin Richard
2011-02-27 07:33:44 UTC
Permalink
On 25 February 2011 15:50, Gregory Petrosyan
Post by Gregory Petrosyan
Oddly softvol=true does not seem to work for FLAC playback.  When a
FLAC file is played it is played at current PCM volume and ignores the
softvol option.  As a hack around this I tried something completely
different from ALSA, but couldn't get it to work either.
This is probably because your FLAC files have sample format different from the
one cmus knows how to scale in software.
Does anybody know a library for scaling the samples in different formats? If
it exists, we may try to integrate it into cmus. Otherwise, the only option is
to create such a library specifically for cmus.  AFAIK mplayer supports
softvol, but I haven't looked at its source yet.
       Gregory
I ran some tests on various FLAC files and figure 'bits per sample'
might be the culprit:

e.g.
file1, bps=16, rate=44100, ch=1&independent, softvol yes
file2, bps=24, rate=44100, ch=1&independent, softvol no
file3, bps=24, rate=44100, ch=2&mid_side, softvol no
file4, bps=16, rate=44100, ch=2&independent, softvol yes

softvol feature probably doesn't handle 24 bit FLAC.
Johannes Weißl
2011-02-27 13:58:41 UTC
Permalink
Post by Justin Richard
Post by Gregory Petrosyan
Oddly softvol=true does not seem to work for FLAC playback.  When a
FLAC file is played it is played at current PCM volume and ignores the
softvol option.  As a hack around this I tried something completely
different from ALSA, but couldn't get it to work either.
This is probably because your FLAC files have sample format different from the
one cmus knows how to scale in software.
Does anybody know a library for scaling the samples in different formats? If
it exists, we may try to integrate it into cmus. Otherwise, the only option is
to create such a library specifically for cmus.  AFAIK mplayer supports
softvol, but I haven't looked at its source yet.
A very popular library for converting samples is libsamplerate, but I
guess it is not needed here. For scaling I don't know, but we can just
copy a little more code from alsa-lib (where the other softvol code is
from).
Post by Justin Richard
I ran some tests on various FLAC files and figure 'bits per sample'
e.g.
file1, bps=16, rate=44100, ch=1&independent, softvol yes
file2, bps=24, rate=44100, ch=1&independent, softvol no
file3, bps=24, rate=44100, ch=2&mid_side, softvol no
file4, bps=16, rate=44100, ch=2&independent, softvol yes
softvol feature probably doesn't handle 24 bit FLAC.
Yes, it is. The scaling function is just aborting for anything other
than 2 channels, 16 bits:

| if (ch != 2 || bits != 16)
| return;

It is relatively easy to enable 24bit, it works on my computer, but I
can't test it on big-endian systems: I have only Qemu (mips) as
development platform, and audio isn't working there for me :-(.
Is there someone with a big-endian platform who can help test the
patches?


Johannes
Johannes Weißl
2011-03-02 03:37:41 UTC
Permalink
Post by Johannes Weißl
It is relatively easy to enable 24bit, it works on my computer, but I
can't test it on big-endian systems: I have only Qemu (mips) as
development platform, and audio isn't working there for me :-(.
Is there someone with a big-endian platform who can help test the
patches?
Update: I discovered that my router is big-endian mips, and managed to
cross-compile and run cmus there. Audio isn't working very well
though (aborting after a few seconds), but madplay works fine. So maybe
there are more problems on big-endian systems.
I attached a few patches that helped to compile cmus.

Also, because the discussion came up a while ago: I wrote initial
support for autotools:
http://gitorious.org/~jmuc/cmus/jw-cmus/commits/autotools
I don't like it as much as the old system though (not so elegant).
Maybe it is still useful for someone.


Johannes
Gregory Petrosyan
2011-03-02 21:06:48 UTC
Permalink
Post by Johannes Weißl
Post by Johannes Weißl
It is relatively easy to enable 24bit, it works on my computer, but I
can't test it on big-endian systems: I have only Qemu (mips) as
development platform, and audio isn't working there for me :-(.
Is there someone with a big-endian platform who can help test the
patches?
Update: I discovered that my router is big-endian mips, and managed to
cross-compile and run cmus there. Audio isn't working very well
though (aborting after a few seconds), but madplay works fine. So maybe
there are more problems on big-endian systems.
I attached a few patches that helped to compile cmus.
Thanks for the patches — I've merged them to master.

I'm curious about your router: how do you get sound out of it? Do you use
networked sound system like PA? Also, does cmus crash after a few seconds of
playback, or is it some other thing happening?

Gregory
Johannes Weißl
2011-03-03 00:15:13 UTC
Permalink
Post by Johannes Weißl
Post by Johannes Weißl
It is relatively easy to enable 24bit, it works on my computer, but I
can't test it on big-endian systems: I have only Qemu (mips) as
development platform, and audio isn't working there for me :-(.
Is there someone with a big-endian platform who can help test the
patches?
Update: I discovered that my router is big-endian mips, and managed to
cross-compile and run cmus there. Audio isn't working very well
though (aborting after a few seconds), but madplay works fine. So maybe
there are more problems on big-endian systems.
I attached a few patches that helped to compile cmus.
Thanks for the patches — I've merged them to master.
Thanks!
I'm curious about your router: how do you get sound out of it? Do you use
networked sound system like PA? Also, does cmus crash after a few seconds of
playback, or is it some other thing happening?
Actually I have an usb fm transmitter (with integrated audio card),
which is supported in openwrt via the kmod-usb-audio module. Strangely
it doesn't work with alsa, but oss (emulation?) is fine.

The sound just halts after 2-3 seconds, no further playback possible, no
crash.
First I thought it has something to do with my setup, but then madplay
worked flawlessly :-(. It is very difficult to debug, because gdb
doesn't show anything useful (maybe my fault).

Does anyone know a cheap big-endian netbook? I would like to have one
as development platform (not just for cmus...). Ben NanoNote is
little-endian.

Johannes
Gregory Petrosyan
2011-03-02 21:36:16 UTC
Permalink
Post by Johannes Weißl
Post by Gregory Petrosyan
Does anybody know a library for scaling the samples in different formats? If
it exists, we may try to integrate it into cmus. Otherwise, the only option is
to create such a library specifically for cmus.  AFAIK mplayer supports
softvol, but I haven't looked at its source yet.
A very popular library for converting samples is libsamplerate, but I
guess it is not needed here. For scaling I don't know, but we can just
copy a little more code from alsa-lib (where the other softvol code is
from).
AFAIK libsamplerate only changes the sample rate of audio, and can't help to
implement softvol/rgscale.
Post by Johannes Weißl
It is relatively easy to enable 24bit, it works on my computer, but I
can't test it on big-endian systems: I have only Qemu (mips) as
development platform, and audio isn't working there for me :-(.
Is there someone with a big-endian platform who can help test the
patches?
If the code comes from tried-and-tested alsa-lib, can't we just assume it is
OK, after some review?

After all, it's better to have RG for 24bit FLAC on LE systems right now, and
fix a (possible) bug on BE systems when (if) it will be discovered, than to
not have RG for 24bit FLAC at all, isn't it? :-)

Gregory
Johannes Weißl
2011-03-03 00:25:33 UTC
Permalink
Post by Gregory Petrosyan
Post by Johannes Weißl
It is relatively easy to enable 24bit, it works on my computer, but I
can't test it on big-endian systems: I have only Qemu (mips) as
development platform, and audio isn't working there for me :-(.
Is there someone with a big-endian platform who can help test the
patches?
If the code comes from tried-and-tested alsa-lib, can't we just assume it is
OK, after some review?
Yes, of course. It would just be cool to test all those WORDS_BIGENDIAN
ifdefs...
Post by Gregory Petrosyan
After all, it's better to have RG for 24bit FLAC on LE systems right now, and
fix a (possible) bug on BE systems when (if) it will be discovered, than to
not have RG for 24bit FLAC at all, isn't it? :-)
Yeah, I will post my patches. What is also on the TODO list: playback of
WAV files other than 16bit. It works if I remove the != 16bit return,
but seeking doesn't (audio is scrambled). Also seeking in APE
files doesn't work, but it works for WMV files (strange?).


Johannes
e***@cs.umn.edu
2011-03-07 03:47:21 UTC
Permalink
In regards to ape, that, from what I recall, is an issue with how we
interact with ffmpeg (though the fact that WMV files work makes me
think it's an ffmpeg issue). I'm not sure if anyone is working on that
at the moment. A different issue is that you can't see APE files in view
5. I'll probably make a different thread about this once I have a chance
to look into it (my dev box is semi-broken at the moment).

Evan
Post by Johannes Weißl
Post by Gregory Petrosyan
Post by Johannes Weißl
It is relatively easy to enable 24bit, it works on my computer, but I
can't test it on big-endian systems: I have only Qemu (mips) as
development platform, and audio isn't working there for me :-(.
Is there someone with a big-endian platform who can help test the
patches?
If the code comes from tried-and-tested alsa-lib, can't we just assume it is
OK, after some review?
Yes, of course. It would just be cool to test all those WORDS_BIGENDIAN
ifdefs...
Post by Gregory Petrosyan
After all, it's better to have RG for 24bit FLAC on LE systems right now, and
fix a (possible) bug on BE systems when (if) it will be discovered, than to
not have RG for 24bit FLAC at all, isn't it? :-)
Yeah, I will post my patches. What is also on the TODO list: playback of
WAV files other than 16bit. It works if I remove the != 16bit return,
but seeking doesn't (audio is scrambled). Also seeking in APE
files doesn't work, but it works for WMV files (strange?).
Johannes
Johannes Weißl
2011-03-07 14:49:25 UTC
Permalink
Works with pulse audio, for e.g. oss other file types with greater
sample size than 16bit (e.g. 24bit flac) also don't work.
To support these files a generic resample method would be needed.
---
wav.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/wav.c b/wav.c
index bd9c8d7..7f1a64e 100644
--- a/wav.c
+++ b/wav.c
@@ -137,7 +137,7 @@ static int wav_open(struct input_plugin_data *ip_data)
rc = -IP_ERROR_FILE_FORMAT;
goto error_exit;
}
- if ((bits != 8 && bits != 16) || channels < 1 || channels > 2) {
+ if ((bits != 8 && bits != 16 && bits != 32) || channels < 1 || channels > 2) {
rc = -IP_ERROR_SAMPLE_FORMAT;
goto error_exit;
}
--
1.7.4.1
Johannes Weißl
2011-03-07 14:49:24 UTC
Permalink
* move swap16 to utils.h (and rename to bswap16)
* add bswap32 function (needed in later commit)
* use builtin functions if available
---
configure | 3 +++
player.c | 12 ++----------
utils.h | 31 +++++++++++++++++++++++++++++++
3 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/configure b/configure
index f71ab84..daf6f10 100755
--- a/configure
+++ b/configure
@@ -301,6 +301,7 @@ DEBUG=1
CONFIG_TREMOR=n
CONFIG_MIKMOD=n
USE_FALLBACK_IP=n
+HAVE_BYTESWAP_H=n
# unset CONFIG_* variables: if check succeeds 'y', otherwise 'n'

USAGE="
@@ -368,6 +369,7 @@ check check_pthread
check check_rtsched
check check_ncurses
check check_iconv
+check_header byteswap.h && HAVE_BYTESWAP_H=y

check check_flac CONFIG_FLAC
check check_mad CONFIG_MAD
@@ -404,6 +406,7 @@ config_header config/mpc.h MPC_SV7
config_header config/mp4.h USE_MPEG4IP
config_header config/curses.h HAVE_RESIZETERM HAVE_USE_DEFAULT_COLORS
config_header config/ffmpeg.h USE_FALLBACK_IP
+config_header config/utils.h HAVE_BYTESWAP_H

makefile_vars bindir datadir libdir mandir exampledir
makefile_vars CONFIG_FLAC CONFIG_MAD CONFIG_MIKMOD CONFIG_MODPLUG CONFIG_MPC CONFIG_VORBIS CONFIG_WAVPACK CONFIG_WAV CONFIG_MP4 CONFIG_AAC CONFIG_FFMPEG
diff --git a/player.c b/player.c
index 9b97969..a6d307c 100644
--- a/player.c
+++ b/player.c
@@ -165,18 +165,10 @@ static const unsigned short soft_vol_db[100] = {
0xcdf1, 0xd71a, 0xe59c, 0xefd3
};

-#ifdef swap16 /* e.g. OpenBSD */
-#undef swap16
-#endif
-static inline unsigned short swap16(unsigned short u)
-{
- return (u << 8) | (u >> 8);
-}
-
static inline void scale_sample(signed short *buf, int i, int vol)
{
#ifdef WORDS_BIGENDIAN
- int sample = (short)swap16(buf[i]);
+ int sample = (short)bswap16(buf[i]);
#else
int sample = buf[i];
#endif
@@ -191,7 +183,7 @@ static inline void scale_sample(signed short *buf, int i, int vol)
sample = 32767;
}
#ifdef WORDS_BIGENDIAN
- buf[i] = swap16(sample);
+ buf[i] = bswap16(sample);
#else
buf[i] = sample;
#endif
diff --git a/utils.h b/utils.h
index f790504..a784465 100644
--- a/utils.h
+++ b/utils.h
@@ -20,6 +20,8 @@
#ifndef _UTILS_H
#define _UTILS_H

+#include "config/utils.h"
+
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@@ -27,6 +29,9 @@
#include <unistd.h>
#include <time.h>
#include <inttypes.h>
+#if HAVE_BYTESWAP_H
+#include <byteswap.h>
+#endif

#define N_ELEMENTS(array) (sizeof(array) / sizeof((array)[0]))

@@ -131,6 +136,32 @@ static inline int is_freeform_true(const char *c)
c[0] == 't' || c[0] == 'T';
}

+static inline uint16_t bswap16(uint16_t u)
+{
+#if defined(bswap_16)
+ /* GNU libc */
+ return bswap_16(u);
+#elif defined(swap16)
+ /* e.g. OpenBSD */
+ return swap16(u);
+#else
+ return (u << 8) | (u >> 8);
+#endif
+}
+
+static inline uint32_t bswap32(uint32_t u)
+{
+#if defined(bswap_32)
+ /* GNU libc */
+ return bswap_32(u);
+#elif defined(swap32)
+ /* e.g. OpenBSD */
+ return swap32(u);
+#else
+ return (u >> 24) | ((u & 0xff0000) >> 8) | ((u & 0xff00) << 8) | ((u & 0xff) << 24);
+#endif
+}
+
static inline uint32_t read_le32(const char *buf)
{
const unsigned char *b = (const unsigned char *)buf;
--
1.7.4.1
Johannes Weißl
2011-03-07 14:49:26 UTC
Permalink
wav files with sample size > 16bit are usually in this format
(e.g. even sox writes it that way).
---
wav.c | 38 ++++++++++++++++++++++++++++++++++----
1 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/wav.c b/wav.c
index 7f1a64e..ff85bb2 100644
--- a/wav.c
+++ b/wav.c
@@ -29,6 +29,9 @@
#include <sys/types.h>
#include <unistd.h>

+#define WAVE_FORMAT_PCM 0x0001U
+#define WAVE_FORMAT_EXTENSIBLE 0xfffeU
+
struct wav_private {
unsigned int pcm_start;
unsigned int pcm_size;
@@ -101,7 +104,7 @@ static int wav_open(struct input_plugin_data *ip_data)
if (rc)
goto error_exit;
if (fmt_size < 16) {
- d_print("size of \"fmt \" chunk is invalid (%d)\n", fmt_size);
+ d_print("size of \"fmt \" chunk is invalid (%u)\n", fmt_size);
rc = -IP_ERROR_FILE_FORMAT;
goto error_exit;
}
@@ -122,7 +125,7 @@ static int wav_open(struct input_plugin_data *ip_data)
goto error_exit;
}
{
- int format_tag, channels, rate, bits;
+ unsigned int format_tag, channels, rate, bits;

format_tag = read_le16(fmt + 0);
channels = read_le16(fmt + 2);
@@ -130,10 +133,37 @@ static int wav_open(struct input_plugin_data *ip_data)
/* 4 bytes, bytes per second */
/* 2 bytes, bytes per sample */
bits = read_le16(fmt + 14);
+ if (format_tag == WAVE_FORMAT_EXTENSIBLE) {
+ unsigned int ext_size, valid_bits;
+ if (fmt_size < 18) {
+ free(fmt);
+ d_print("size of \"fmt \" chunk is invalid (%u)\n", fmt_size);
+ rc = -IP_ERROR_FILE_FORMAT;
+ goto error_exit;
+ }
+ ext_size = read_le16(fmt + 16);
+ if (ext_size < 22) {
+ free(fmt);
+ d_print("size of \"fmt \" chunk extension is invalid (%u)\n", ext_size);
+ rc = -IP_ERROR_FILE_FORMAT;
+ goto error_exit;
+ }
+ valid_bits = read_le16(fmt + 18);
+ if (valid_bits != bits) {
+ free(fmt);
+ d_print("padded samples are not supported (%u != %u)\n", bits, valid_bits);
+ rc = -IP_ERROR_FILE_FORMAT;
+ goto error_exit;
+ }
+ /* speaker position mask */
+ read_le32(fmt + 20);
+ format_tag = read_le16(fmt + 24);
+ /* ignore rest of extension tag */
+ }
free(fmt);

- if (format_tag != 1) {
- d_print("invalid format tag %d, should be 1\n", format_tag);
+ if (format_tag != WAVE_FORMAT_PCM) {
+ d_print("invalid format tag %u, should be 1\n", format_tag);
rc = -IP_ERROR_FILE_FORMAT;
goto error_exit;
}
--
1.7.4.1
Johannes Weißl
2011-03-07 14:49:27 UTC
Permalink
replay gain and softvol are now supported for 24bit FLAC files (which
seem to have sample size of 32bit internally).
---
player.c | 88 ++++++++++++++++++++++++++++++++++++++++++-------------------
1 files changed, 60 insertions(+), 28 deletions(-)

diff --git a/player.c b/player.c
index a6d307c..fa6db53 100644
--- a/player.c
+++ b/player.c
@@ -165,35 +165,71 @@ static const unsigned short soft_vol_db[100] = {
0xcdf1, 0xd71a, 0xe59c, 0xefd3
};

-static inline void scale_sample(signed short *buf, int i, int vol)
+static inline void scale_sample_int16_t(int16_t *buf, int i, int vol, int swap)
{
-#ifdef WORDS_BIGENDIAN
- int sample = (short)bswap16(buf[i]);
-#else
- int sample = buf[i];
-#endif
+ int32_t sample = swap ? (int16_t)bswap16(buf[i]) : buf[i];

if (sample < 0) {
sample = (sample * vol - SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
- if (sample < -32768)
- sample = -32768;
+ if (sample < INT16_MIN)
+ sample = INT16_MIN;
} else {
sample = (sample * vol + SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
- if (sample > 32767)
- sample = 32767;
+ if (sample > INT16_MAX)
+ sample = INT16_MAX;
}
+ buf[i] = swap ? bswap16(sample) : sample;
+}
+
+static inline void scale_sample_int32_t(int32_t *buf, int i, int vol, int swap)
+{
+ int64_t sample = swap ? (int32_t)bswap32(buf[i]) : buf[i];
+
+ if (sample < 0) {
+ sample = (sample * vol - SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
+ if (sample < INT32_MIN)
+ sample = INT32_MIN;
+ } else {
+ sample = (sample * vol + SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
+ if (sample > INT32_MAX)
+ sample = INT32_MAX;
+ }
+ buf[i] = swap ? bswap32(sample) : sample;
+}
+
+static inline int sf_need_swap(sample_format_t sf)
+{
#ifdef WORDS_BIGENDIAN
- buf[i] = bswap16(sample);
+ return !sf_get_bigendian(sf);
#else
- buf[i] = sample;
+ return sf_get_bigendian(sf);
#endif
}

+#define SCALE_SAMPLES(TYPE, buffer, count, l, r, swap) \
+{ \
+ const int frames = count / sizeof(TYPE) / 2; \
+ TYPE *buf = (TYPE *) buffer; \
+ int i; \
+ /* avoid underflowing -32768 to 32767 when scale is 65536 */ \
+ if (l != SOFT_VOL_SCALE && r != SOFT_VOL_SCALE) { \
+ for (i = 0; i < frames; i++) { \
+ scale_sample_##TYPE(buf, i * 2, l, swap); \
+ scale_sample_##TYPE(buf, i * 2 + 1, r, swap); \
+ } \
+ } else if (l != SOFT_VOL_SCALE) { \
+ for (i = 0; i < frames; i++) \
+ scale_sample_##TYPE(buf, i * 2, l, swap); \
+ } else if (r != SOFT_VOL_SCALE) { \
+ for (i = 0; i < frames; i++) \
+ scale_sample_##TYPE(buf, i * 2 + 1, r, swap); \
+ } \
+}
+
static void scale_samples(char *buffer, unsigned int *countp)
{
- signed short *buf;
unsigned int count = *countp;
- int ch, bits, l, r, i;
+ int ch, bits, l, r;

BUG_ON(scale_pos < consumer_pos);

@@ -206,15 +242,16 @@ static void scale_samples(char *buffer, unsigned int *countp)
count -= offs;
}
scale_pos += count;
- buf = (signed short *)buffer;

if (replaygain_scale == 1.0 && soft_vol_l == 100 && soft_vol_r == 100)
return;

ch = sf_get_channels(buffer_sf);
bits = sf_get_bits(buffer_sf);
- if (ch != 2 || bits != 16)
+ if (ch != 2 || (bits != 16 && bits != 32)) {
+ d_print("scaling not supported for %u bits %u channel audio\n", bits, ch);
return;
+ }

l = SOFT_VOL_SCALE;
r = SOFT_VOL_SCALE;
@@ -226,18 +263,13 @@ static void scale_samples(char *buffer, unsigned int *countp)
l *= replaygain_scale;
r *= replaygain_scale;

- /* avoid underflowing -32768 to 32767 when scale is 65536 */
- if (l != SOFT_VOL_SCALE && r != SOFT_VOL_SCALE) {
- for (i = 0; i < count / 4; i++) {
- scale_sample(buf, i * 2, l);
- scale_sample(buf, i * 2 + 1, r);
- }
- } else if (l != SOFT_VOL_SCALE) {
- for (i = 0; i < count / 4; i++)
- scale_sample(buf, i * 2, l);
- } else if (r != SOFT_VOL_SCALE) {
- for (i = 0; i < count / 4; i++)
- scale_sample(buf, i * 2 + 1, r);
+ switch (bits) {
+ case 16:
+ SCALE_SAMPLES(int16_t, buffer, count, l, r, sf_need_swap(buffer_sf));
+ break;
+ case 32:
+ SCALE_SAMPLES(int32_t, buffer, count, l, r, sf_need_swap(buffer_sf));
+ break;
}
}
--
1.7.4.1
Johannes Weißl
2011-03-07 15:03:29 UTC
Permalink
---
flac.c | 16 +++-------------
1 files changed, 3 insertions(+), 13 deletions(-)

diff --git a/flac.c b/flac.c
index 66f5a9f..7bdf0ec 100644
--- a/flac.c
+++ b/flac.c
@@ -2,6 +2,7 @@
#include "comment.h"
#include "xmalloc.h"
#include "debug.h"
+#include "utils.h"

#include <FLAC/export.h>

@@ -170,19 +171,8 @@ static int eof_cb(const Dec *dec, void *data)

#if defined(WORDS_BIGENDIAN)

-static inline uint16_t LE16(uint16_t x)
-{
- return (x >> 8) | (x << 8);
-}
-
-static inline uint32_t LE32(uint32_t x)
-{
- uint32_t x3 = x << 24;
- uint32_t x0 = x >> 24;
- uint32_t x2 = (x & 0xff00) << 8;
- uint32_t x1 = (x >> 8) & 0xff00;
- return x3 | x2 | x1 | x0;
-}
+#define LE16(x) bswap16(x)
+#define LE32(x) bswap32(x)

#else
--
1.7.4.1
Johannes Weißl
2011-03-07 23:40:12 UTC
Permalink
---
oss.c | 21 +++++++++++++++++++++
1 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/oss.c b/oss.c
index 753c293..a9c2223 100644
--- a/oss.c
+++ b/oss.c
@@ -20,6 +20,7 @@
#include "op.h"
#include "sf.h"
#include "xmalloc.h"
+#include "debug.h"

#if defined(__OpenBSD__)
#include <soundcard.h>
@@ -48,6 +49,14 @@ static int oss_reset(void)
return 0;
}

+/* defined only in OSSv4, but seem to work in OSSv3 */
+#ifndef AFMT_S32_LE
+#define AFMT_S32_LE 0x00001000
+#endif
+#ifndef AFMT_S32_BE
+#define AFMT_S32_BE 0x00002000
+#endif
+
static int oss_set_sf(sample_format_t sf)
{
int tmp, log2_fragment_size, nr_fragments, bytes_per_second;
@@ -78,7 +87,16 @@ static int oss_set_sf(sample_format_t sf)
} else {
tmp = AFMT_U8;
}
+ } else if (sf_get_bits(oss_sf) == 32 && sf_get_signed(oss_sf)) {
+ if (sf_get_bigendian(oss_sf)) {
+ tmp = AFMT_S32_BE;
+ } else {
+ tmp = AFMT_S32_LE;
+ }
} else {
+ d_print("unsupported sample format: %c%u_%s\n",
+ sf_get_signed(oss_sf) ? 'S' : 'U', sf_get_bits(oss_sf),
+ sf_get_bigendian(oss_sf) ? "BE" : "LE");
return -1;
}
if (ioctl(oss_fd, SNDCTL_DSP_SAMPLESIZE, &tmp) == -1)
@@ -143,9 +161,12 @@ static int oss_exit(void)

static int oss_open(sample_format_t sf)
{
+ int oss_version = 0;
oss_fd = open(oss_dsp_device, O_WRONLY);
if (oss_fd == -1)
return -1;
+ ioctl(oss_fd, OSS_GETVERSION, &oss_version);
+ d_print("oss version: %#08x\n", oss_version);
if (oss_set_sf(sf) == -1) {
oss_close();
return -1;
--
1.7.4.1
Johannes Weißl
2011-03-08 00:21:48 UTC
Permalink
Also don't quit for 24bit wave files, as they are supported now.
---
wav.c | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/wav.c b/wav.c
index ff85bb2..a64ebdd 100644
--- a/wav.c
+++ b/wav.c
@@ -39,6 +39,8 @@ struct wav_private {

/* size of one second of data */
unsigned int sec_size;
+
+ unsigned int frame_size;
};

static int read_chunk_header(int fd, const char *name, unsigned int *size)
@@ -167,7 +169,7 @@ static int wav_open(struct input_plugin_data *ip_data)
rc = -IP_ERROR_FILE_FORMAT;
goto error_exit;
}
- if ((bits != 8 && bits != 16 && bits != 32) || channels < 1 || channels > 2) {
+ if ((bits != 8 && bits != 16 && bits != 24 && bits != 32) || channels < 1 || channels > 2) {
rc = -IP_ERROR_SAMPLE_FORMAT;
goto error_exit;
}
@@ -186,6 +188,7 @@ static int wav_open(struct input_plugin_data *ip_data)
priv->pcm_start = rc;

priv->sec_size = sf_get_second_size(ip_data->sf);
+ priv->frame_size = sf_get_frame_size(ip_data->sf);
priv->pos = 0;

d_print("pcm start: %u\n", priv->pcm_start);
@@ -247,8 +250,8 @@ static int wav_seek(struct input_plugin_data *ip_data, double _offset)
off_t rc;

offset = (unsigned int)(_offset * (double)priv->sec_size + 0.5);
- /* align to 4 bytes (2 * 16 / 8) */
- offset &= ~3U;
+ /* align to frame size */
+ offset -= offset % priv->frame_size;
priv->pos = offset;
rc = lseek(ip_data->fd, priv->pcm_start + offset, SEEK_SET);
if (rc == (off_t)-1)
--
1.7.4.1
Gregory Petrosyan
2011-03-08 15:32:40 UTC
Permalink
Thanks a lot for the patchset Johannes, merged it into pu!

Gregory
Johannes Weißl
2011-03-17 00:14:57 UTC
Permalink
* Support softvol and replaygain scaling for 24bit audio (e.g. wav and
wavpack).
* Change CHUNK_SIZE to (60 * 1024). This is required to support 24bit
scaling.
* Remove debug message again in scale_samples().
scale_samples() gets called really often, so this spams the debug log.
Also scaling is now supported for all sample formats cmus can read, so
this case should happen a lot less often.
---
buffer.h | 3 ++-
player.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/buffer.h b/buffer.h
index 3880064..e8210ed 100644
--- a/buffer.h
+++ b/buffer.h
@@ -1,7 +1,8 @@
#ifndef _BUFFER_H
#define _BUFFER_H

-#define CHUNK_SIZE (64 * 1024)
+/* must be a multiple of any supported frame size */
+#define CHUNK_SIZE (60 * 1024)

extern unsigned int buffer_nr_chunks;

diff --git a/player.c b/player.c
index 33ca97b..4c56d35 100644
--- a/player.c
+++ b/player.c
@@ -181,6 +181,21 @@ static inline void scale_sample_int16_t(int16_t *buf, int i, int vol, int swap)
buf[i] = swap ? bswap16(sample) : sample;
}

+static inline int32_t scale_sample_s24le(int32_t s, int vol)
+{
+ int64_t sample = s;
+ if (sample < 0) {
+ sample = (sample * vol - SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
+ if (sample < -0x800000)
+ sample = -0x800000;
+ } else {
+ sample = (sample * vol + SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
+ if (sample > 0x7fffff)
+ sample = 0x7fffff;
+ }
+ return sample;
+}
+
static inline void scale_sample_int32_t(int32_t *buf, int i, int vol, int swap)
{
int64_t sample = swap ? (int32_t)bswap32(buf[i]) : buf[i];
@@ -226,6 +241,44 @@ static inline int sf_need_swap(sample_format_t sf)
} \
}

+static inline int32_t read_s24le(const char *buf)
+{
+ const unsigned char *b = (const unsigned char *) buf;
+ return b[0] | (b[1] << 8) | (((const signed char *) buf)[2] << 16);
+}
+
+static inline void write_s24le(char *buf, int32_t x)
+{
+ unsigned char *b = (unsigned char *) buf;
+ b[0] = x;
+ b[1] = x >> 8;
+ b[2] = x >> 16;
+}
+
+static void scale_samples_s24le(char *buf, unsigned int count, int l, int r)
+{
+ int frames = count / 3 / 2;
+ if (l != SOFT_VOL_SCALE && r != SOFT_VOL_SCALE) {
+ while (frames--) {
+ write_s24le(buf, scale_sample_s24le(read_s24le(buf), l));
+ buf += 3;
+ write_s24le(buf, scale_sample_s24le(read_s24le(buf), r));
+ buf += 3;
+ }
+ } else if (l != SOFT_VOL_SCALE) {
+ while (frames--) {
+ write_s24le(buf, scale_sample_s24le(read_s24le(buf), l));
+ buf += 3 * 2;
+ }
+ } else if (r != SOFT_VOL_SCALE) {
+ buf += 3;
+ while (frames--) {
+ write_s24le(buf, scale_sample_s24le(read_s24le(buf), r));
+ buf += 3 * 2;
+ }
+ }
+}
+
static void scale_samples(char *buffer, unsigned int *countp)
{
unsigned int count = *countp;
@@ -248,10 +301,8 @@ static void scale_samples(char *buffer, unsigned int *countp)

ch = sf_get_channels(buffer_sf);
bits = sf_get_bits(buffer_sf);
- if (ch != 2 || (bits != 16 && bits != 32)) {
- d_print("scaling not supported for %u bits %u channel audio\n", bits, ch);
+ if (ch != 2 || (bits != 16 && bits != 24 && bits != 32))
return;
- }

l = SOFT_VOL_SCALE;
r = SOFT_VOL_SCALE;
@@ -267,6 +318,10 @@ static void scale_samples(char *buffer, unsigned int *countp)
case 16:
SCALE_SAMPLES(int16_t, buffer, count, l, r, sf_need_swap(buffer_sf));
break;
+ case 24:
+ if (likely(!sf_get_bigendian(buffer_sf)))
+ scale_samples_s24le(buffer, count, l, r);
+ break;
case 32:
SCALE_SAMPLES(int32_t, buffer, count, l, r, sf_need_swap(buffer_sf));
break;
--
1.7.4.1
Gregory Petrosyan
2011-03-29 17:40:09 UTC
Permalink
Post by Johannes Weißl
+ if (likely(!sf_get_bigendian(buffer_sf)))
+ scale_samples_s24le(buffer, count, l, r);
+ break;
No need for likely() here, but whatever, merged into master! :-)

Gregory

Loading...