summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar waker <wakeroid@gmail.com>2010-11-13 22:51:12 +0100
committerGravatar waker <wakeroid@gmail.com>2010-11-13 22:51:12 +0100
commit8eada3d6211baeac22c9d0f1977bc90f428247d5 (patch)
tree164053c4ce7cabb207976875b0026e180b75dc4c
parent7e2a8b73bc4ccf17e1be4163b003a249badd509e (diff)
added channel remapping and some format conversions
-rw-r--r--plugins/alsa/alsa.c11
-rw-r--r--premix.c154
2 files changed, 150 insertions, 15 deletions
diff --git a/plugins/alsa/alsa.c b/plugins/alsa/alsa.c
index be744b34..31e179ae 100644
--- a/plugins/alsa/alsa.c
+++ b/plugins/alsa/alsa.c
@@ -191,7 +191,7 @@ palsa_set_hw_params (ddb_waveformat_t *fmt) {
plugin.fmt.samplerate = val;
trace ("chosen samplerate: %d Hz\n", val);
- if ((err = snd_pcm_hw_params_set_channels (audio, hw_params, /*fmt->channels*/6)) < 0) {
+ if ((err = snd_pcm_hw_params_set_channels (audio, hw_params, fmt->channels)) < 0) {
fprintf (stderr, "cannot set channel count (%s)\n",
snd_strerror (err));
goto error;
@@ -218,6 +218,7 @@ palsa_set_hw_params (ddb_waveformat_t *fmt) {
goto error;
}
+ plugin.fmt.is_float = 0;
switch (sample_fmt) {
case SND_PCM_FORMAT_S8:
plugin.fmt.bps = 8;
@@ -234,10 +235,16 @@ palsa_set_hw_params (ddb_waveformat_t *fmt) {
case SND_PCM_FORMAT_S32_LE:
plugin.fmt.bps = 32;
break;
+ case SND_PCM_FORMAT_FLOAT_LE:
+ case SND_PCM_FORMAT_FLOAT_BE:
+ plugin.fmt.bps = 32;
+ plugin.fmt.is_float = 1;
+ break;
}
+ trace ("chosen bps: %d (%s)\n", plugin.fmt.bps, plugin.fmt.is_float ? "float" : "int");
+
plugin.fmt.channels = nchan;
- plugin.fmt.is_float = 0;
plugin.fmt.is_multichannel = 0;
plugin.fmt.channelmask = 0;
if (nchan == 1) {
diff --git a/premix.c b/premix.c
index 36fd4147..0c73fe5a 100644
--- a/premix.c
+++ b/premix.c
@@ -26,9 +26,120 @@
#define trace(...) { fprintf(stderr, __VA_ARGS__); }
//#define trace(fmt,...)
-void
-pcm_write_sample (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output) {
- memcpy (output, input, 2);
+
+static inline void
+pcm_write_samples_8_to_8 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
+ for (int s = 0; s < nsamples; s++) {
+ for (int c = 0; c < inputfmt->channels; c++) {
+ if (channelmap[c] != -1) {
+ *(output + (outputfmt->bps >> 3) * channelmap[c]) = *input;
+ }
+ input++;
+ }
+ output += outputsamplesize;
+ }
+}
+
+static inline void
+pcm_write_samples_8_to_16 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
+ for (int s = 0; s < nsamples; s++) {
+ for (int c = 0; c < inputfmt->channels; c++) {
+ if (channelmap[c] != -1) {
+ *((int16_t*)(output + (outputfmt->bps >> 3) * channelmap[c])) = (int16_t)(*input) << 8;
+ }
+ input++;
+ }
+ output += outputsamplesize;
+ }
+}
+
+static inline void
+pcm_write_samples_16_to_16 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
+ for (int s = 0; s < nsamples; s++) {
+ for (int c = 0; c < inputfmt->channels; c++) {
+ if (channelmap[c] != -1) {
+ *((int16_t*)(output + (outputfmt->bps >> 3) * channelmap[c])) = *((int16_t*)input);
+ }
+ input += 2;
+ }
+ output += outputsamplesize;
+ }
+}
+
+static inline void
+pcm_write_samples_16_to_8 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
+ for (int s = 0; s < nsamples; s++) {
+ for (int c = 0; c < inputfmt->channels; c++) {
+ if (channelmap[c] != -1) {
+ *((int8_t*)(output + (outputfmt->bps >> 3) * channelmap[c])) = *((int16_t*)input) >> 8;
+ }
+ input += 2;
+ }
+ output += outputsamplesize;
+ }
+}
+
+static inline void
+pcm_write_samples_16_to_24 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
+ for (int s = 0; s < nsamples; s++) {
+ for (int c = 0; c < inputfmt->channels; c++) {
+ if (channelmap[c] != -1) {
+ char *out = output + (outputfmt->bps >> 3) * channelmap[c];
+ out[0] = 0;
+ out[1] = input[0];
+ out[2] = input[1];
+ }
+ input += 2;
+ }
+ output += outputsamplesize;
+ }
+}
+
+static inline void
+pcm_write_samples_16_to_32 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
+ for (int s = 0; s < nsamples; s++) {
+ for (int c = 0; c < inputfmt->channels; c++) {
+ if (channelmap[c] != -1) {
+ char *out = output + (outputfmt->bps >> 3) * channelmap[c];
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = input[0];
+ out[3] = input[1];
+ }
+ input += 2;
+ }
+ output += outputsamplesize;
+ }
+}
+
+static inline void
+pcm_write_samples_16_to_float (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
+ for (int s = 0; s < nsamples; s++) {
+ for (int c = 0; c < inputfmt->channels; c++) {
+ if (channelmap[c] != -1) {
+ float sample = (*((int16_t*)input)) / (float)0x7fff;
+ *((float *)(output + (outputfmt->bps >> 3) * channelmap[c])) = sample;
+ }
+ input += 2;
+ }
+ output += outputsamplesize;
+ }
+}
+
+static inline void
+pcm_write_samples_24_to_24 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
+ for (int s = 0; s < nsamples; s++) {
+ for (int c = 0; c < inputfmt->channels; c++) {
+ if (channelmap[c] != -1) {
+ char *out = output + (outputfmt->bps >> 3) * channelmap[c];
+ out[0] = input[0];
+ out[1] = input[1];
+ out[2] = input[2];
+ }
+ input += 3;
+ }
+ output += outputsamplesize;
+ }
}
int
@@ -50,7 +161,7 @@ pcm_convert (const ddb_waveformat_t * restrict inputfmt, const char * restrict i
inputbitmask <<= 1;
}
if (!(inputfmt->channelmask & inputbitmask)) {
- trace ("pcm_convert: channelmask doesn't correspond inputfmt (channels=%d, channelmask=%X)!", inputfmt->channels, inputfmt->channelmask);
+ trace ("pcm_convert: channelmask doesn't correspond inputfmt (channels=%d, channelmask=%X)!\n", inputfmt->channels, inputfmt->channelmask);
break;
}
if (outputfmt->channelmask & inputbitmask) {
@@ -66,7 +177,7 @@ pcm_convert (const ddb_waveformat_t * restrict inputfmt, const char * restrict i
}
outchannels |= outputbitmask;
channelmap[i] = o; // input channel i going to output channel o
- trace ("channelmap[%d]=%d\n", i, o);
+ //trace ("channelmap[%d]=%d\n", i, o);
}
inputbitmask <<= 1;
}
@@ -75,14 +186,31 @@ pcm_convert (const ddb_waveformat_t * restrict inputfmt, const char * restrict i
// some of the channels are not used
memset (output, 0, nsamples * outputsamplesize);
}
- for (int s = 0; s < nsamples; s++) {
- for (int c = 0; c < inputfmt->channels; c++) {
- if (channelmap[c] != -1) {
- pcm_write_sample (inputfmt, input, outputfmt, output + (outputfmt->bps >> 3) * channelmap[c]);
- }
- input += inputfmt->bps >> 3;
- }
- output += outputsamplesize;
+
+ // FIXME: access through function pointer table
+ if (inputfmt->bps == 8 && outputfmt->bps == 8) {
+ pcm_write_samples_8_to_8 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize);
+ }
+ if (inputfmt->bps == 8 && outputfmt->bps == 16) {
+ pcm_write_samples_8_to_16 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize);
+ }
+ if (inputfmt->bps == 16 && outputfmt->bps == 16) {
+ pcm_write_samples_16_to_16 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize);
+ }
+ else if (inputfmt->bps == 16 && outputfmt->bps == 8) {
+ pcm_write_samples_16_to_8 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize);
+ }
+ else if (inputfmt->bps == 16 && outputfmt->bps == 24) {
+ pcm_write_samples_16_to_24 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize);
+ }
+ else if (inputfmt->bps == 16 && outputfmt->bps == 32 && !outputfmt->is_float) {
+ pcm_write_samples_16_to_32 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize);
+ }
+ else if (inputfmt->bps == 16 && outputfmt->bps == 32 && outputfmt->is_float) {
+ pcm_write_samples_16_to_float (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize);
+ }
+ else if (inputfmt->bps == 24 && outputfmt->bps == 24) {
+ pcm_write_samples_24_to_24 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize);
}
}
return nsamples * outputsamplesize;