configure shout encoding quality and audio format

git-svn-id: https://svn.musicpd.org/mpd/trunk@2307 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
Warren Dukes 2004-10-23 01:04:58 +00:00
parent 413bf61ea1
commit 12597322a2
8 changed files with 167 additions and 56 deletions

View File

@ -66,22 +66,27 @@ void getOutputAudioFormat(AudioFormat * inAudioFormat,
void initAudioConfig() {
char * conf = getConf()[CONF_AUDIO_OUTPUT_FORMAT];
char * test;
if(NULL == conf) return;
audio_configFormat = malloc(sizeof(AudioFormat));
memset(audio_configFormat,0,sizeof(AudioFormat));
if(0 != parseAudioConfig(audio_configFormat, conf)) exit(EXIT_FAILURE);
}
audio_configFormat->sampleRate = strtol(conf,&test,10);
int parseAudioConfig(AudioFormat * audioFormat, char * conf) {
char * test;
memset(audioFormat,0,sizeof(AudioFormat));
audioFormat->sampleRate = strtol(conf,&test,10);
if(*test!=':') {
ERROR("error parsing audio output format: %s\n",conf);
exit(EXIT_FAILURE);
return -1;
}
/*switch(audio_configFormat->sampleRate) {
/*switch(audioFormat->sampleRate) {
case 48000:
case 44100:
case 32000:
@ -89,47 +94,50 @@ void initAudioConfig() {
break;
default:
ERROR("sample rate %i can not be used for audio output\n",
(int)audio_configFormat->sampleRate);
exit(EXIT_FAILURE);
(int)audioFormat->sampleRate);
return -1
}*/
if(audio_configFormat->sampleRate <= 0) {
if(audioFormat->sampleRate <= 0) {
ERROR("sample rate %i is not >= 0\n",
(int)audio_configFormat->sampleRate);
exit(EXIT_FAILURE);
(int)audioFormat->sampleRate);
return -1;
}
audio_configFormat->bits = strtol(test+1,&test,10);
audioFormat->bits = strtol(test+1,&test,10);
if(*test!=':') {
ERROR("error parsing audio output format: %s\n",conf);
exit(EXIT_FAILURE);
return -1;
}
switch(audio_configFormat->bits) {
switch(audioFormat->bits) {
case 16:
break;
default:
ERROR("bits %i can not be used for audio output\n",
(int)audio_configFormat->bits);
exit(EXIT_FAILURE);
(int)audioFormat->bits);
return -1;
}
audio_configFormat->channels = strtol(test+1,&test,10);
audioFormat->channels = strtol(test+1,&test,10);
if(*test!='\0') {
ERROR("error parsing audio output format: %s\n",conf);
exit(EXIT_FAILURE);
return -1;
}
switch(audio_configFormat->channels) {
switch(audioFormat->channels) {
case 1:
case 2:
break;
default:
ERROR("channels %i can not be used for audio output\n",
(int)audio_configFormat->channels);
exit(EXIT_FAILURE);
(int)audioFormat->channels);
return -1;
}
return 0;
}
void finishAudioConfig() {

View File

@ -35,6 +35,8 @@ typedef struct _AudioFormat {
void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat);
int parseAudioConfig(AudioFormat * audioFormat, char * conf);
void initAudioConfig();
void finishAudioConfig();

View File

@ -24,6 +24,7 @@
#include "conf.h"
#include "log.h"
#include "sig_handlers.h"
#include "pcm_utils.h"
#include <stdlib.h>
#include <string.h>
@ -54,6 +55,15 @@ typedef struct _ShoutData {
vorbis_comment vc;
int serialno;
float quality;
AudioFormat outAudioFormat;
AudioFormat inAudioFormat;
char * convBuffer;
long convBufferLen;
/* shoud we convert the audio to a different format? */
int audioFormatConvert;
} ShoutData;
static ShoutData * newShoutData() {
@ -61,6 +71,8 @@ static ShoutData * newShoutData() {
ret->shoutConn = shout_new();
ret->serialno = rand();
ret->convBuffer = NULL;
ret->convBufferLen = 0;
return ret;
}
@ -112,6 +124,16 @@ static int shout_initDriver(AudioOutput * audioOutput) {
exit(EXIT_FAILURE);
}
if(!getConf()[CONF_SHOUT_QUALITY]) {
ERROR("shout host defined but not shout quality\n");
exit(EXIT_FAILURE);
}
if(!getConf()[CONF_SHOUT_FORMAT]) {
ERROR("shout host defined but not shout format\n");
exit(EXIT_FAILURE);
}
host = getConf()[CONF_SHOUT_HOST];
passwd = getConf()[CONF_SHOUT_PASSWD];
user = getConf()[CONF_SHOUT_USER];
@ -126,6 +148,20 @@ static int shout_initDriver(AudioOutput * audioOutput) {
exit(EXIT_FAILURE);
}
sd->quality = strtod(getConf()[CONF_SHOUT_QUALITY], &test);
if(*test != '\0' || sd->quality < 0.0 || sd->quality > 10.0) {
ERROR("shout quality \"%s\" is not a number in the range "
"0-10\n", getConf()[CONF_SHOUT_QUALITY]);
exit(EXIT_FAILURE);
}
if(0 != parseAudioConfig(&(sd->outAudioFormat),
getConf()[CONF_SHOUT_FORMAT]) )
{
exit(EXIT_FAILURE);
}
if(shout_set_host(sd->shoutConn, host) != SHOUTERR_SUCCESS ||
shout_set_port(sd->shoutConn, port) != SHOUTERR_SUCCESS ||
shout_set_password(sd->shoutConn, passwd) != SHOUTERR_SUCCESS ||
@ -202,8 +238,8 @@ static int shout_openDevice(AudioOutput * audioOutput,
vorbis_info_init(&(sd->vi));
if( 0 != vorbis_encode_init_vbr(&(sd->vi), audioFormat->channels,
audioFormat->sampleRate, 0.5) )
if( 0 != vorbis_encode_init_vbr(&(sd->vi), sd->outAudioFormat.channels,
sd->outAudioFormat.sampleRate, sd->quality) )
{
ERROR("problem seting up vorbis encoder for shout\n");
vorbis_info_clear(&(sd->vi));
@ -230,19 +266,59 @@ static int shout_openDevice(AudioOutput * audioOutput,
write_page(sd);
}
memcpy(&(sd->inAudioFormat), audioFormat, sizeof(AudioFormat));
if(0 == memcmp(&(sd->inAudioFormat), &(sd->outAudioFormat),
sizeof(AudioFormat)))
{
sd->audioFormatConvert = 0;
}
else sd->audioFormatConvert = 1;
return 0;
}
static void shout_convertAudioFormat(ShoutData * sd, char ** chunkArgPtr,
int * sizeArgPtr)
{
int size = pcm_sizeOfOutputBufferForAudioFormatConversion(
&(sd->inAudioFormat), *sizeArgPtr,
&(sd->outAudioFormat));
if(size > sd->convBufferLen) {
sd->convBuffer = realloc(sd->convBuffer, size);
sd->convBufferLen = size;
}
pcm_convertAudioFormat(&(sd->inAudioFormat), *chunkArgPtr, *sizeArgPtr,
&(sd->outAudioFormat), sd->convBuffer);
*sizeArgPtr = size;
*chunkArgPtr = sd->convBuffer;
}
static int shout_play(AudioOutput * audioOutput, char * playChunk, int size) {
int i,j;
ShoutData * sd = (ShoutData *)audioOutput->data;
float ** vorbbuf;
int samples;
int bytes = sd->outAudioFormat.bits/8;
float **vorbbuf = vorbis_analysis_buffer(&(sd->vd), size/4);
if(sd->audioFormatConvert) {
shout_convertAudioFormat(sd, &playChunk, &size);
}
for(i=0, j=0; i < size; i+=4, j++) {
vorbbuf[0][j] = (*((mpd_sint16 *)(playChunk+i))) / 32768.0;
vorbbuf[1][j] = (*((mpd_sint16 *)(playChunk+i+2))) / 32768.0;
samples = size/(bytes*sd->outAudioFormat.channels);
/* this is for only 16-bit audio */
vorbbuf = vorbis_analysis_buffer(&(sd->vd), samples);
for(i=0; i<samples; i++) {
for(j=0; j<sd->outAudioFormat.channels; j++) {
vorbbuf[j][i] = (*((mpd_sint16 *)playChunk)) / 32768.0;
playChunk += bytes;
}
}
vorbis_analysis_wrote(&(sd->vd), size/4);

View File

@ -37,7 +37,7 @@
#define CONF_COMMENT '#'
#define CONF_NUMBER_OF_PARAMS 42
#define CONF_NUMBER_OF_PARAMS 43
#define CONF_NUMBER_OF_PATHS 6
#define CONF_NUMBER_OF_REQUIRED 5
#define CONF_NUMBER_OF_ALLOW_CATS 1
@ -138,7 +138,8 @@ char ** readConf(char * file) {
"shout_name",
"shout_user",
"shout_quality",
"id3v1_encoding"
"id3v1_encoding",
"shout_format"
};
int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {

View File

@ -63,6 +63,7 @@
#define CONF_SHOUT_USER 39
#define CONF_SHOUT_QUALITY 40
#define CONF_ID3V1_ENCODING 41
#define CONF_SHOUT_FORMAT 42
#define CONF_CAT_CHAR "\n"

View File

@ -80,7 +80,7 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
}
else {
datalen = pcm_sizeOfOutputBufferForAudioFormatConversion(
&(dc->audioFormat), dataIn, dataInLen,
&(dc->audioFormat), dataInLen,
&(cb->audioFormat));
if(datalen > convBufferLen) {
convBuffer = realloc(convBuffer,datalen);

View File

@ -153,7 +153,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
int dataBitLen;
assert(outFormat->bits==16);
assert(outFormat->channels==2);
assert(outFormat->channels==2 || outFormat->channels==1);
/* converts */
switch(inFormat->bits) {
@ -185,32 +185,55 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
}
/* converts only between 16 bit audio between mono and stereo */
switch(inFormat->channels) {
case 1:
dataChannelLen = (dataBitLen >> 1) << 2;
if(dataChannelLen > channelConvBufferLength) {
channelConvBuffer = realloc(channelConvBuffer,
dataChannelLen);
channelConvBufferLength = dataChannelLen;
}
dataChannelConv = channelConvBuffer;
{
mpd_sint16 * in = (mpd_sint16 *)dataBitConv;
mpd_sint16 * out = (mpd_sint16 *)dataChannelConv;
int i, inSamples = dataBitLen >> 1;
for(i=0;i<inSamples;i++) {
*out++ = *in;
*out++ = *in++;
}
}
break;
case 2:
if(inFormat->channels == outFormat->channels)
{
dataChannelConv = dataBitConv;
dataChannelLen = dataBitLen;
break;
default:
ERROR("only 1 or 2 channels are supported for conversion!\n");
exit(EXIT_FAILURE);
}
else {
switch(inFormat->channels) {
/* convert from 1 -> 2 channels */
case 1:
dataChannelLen = (dataBitLen >> 1) << 2;
if(dataChannelLen > channelConvBufferLength) {
channelConvBuffer = realloc(channelConvBuffer,
dataChannelLen);
channelConvBufferLength = dataChannelLen;
}
dataChannelConv = channelConvBuffer;
{
mpd_sint16 * in = (mpd_sint16 *)dataBitConv;
mpd_sint16 * out = (mpd_sint16 *)dataChannelConv;
int i, inSamples = dataBitLen >> 1;
for(i=0;i<inSamples;i++) {
*out++ = *in;
*out++ = *in++;
}
}
break;
/* convert from 2 -> 1 channels */
case 2:
dataChannelLen = dataBitLen >> 1;
if(dataChannelLen > channelConvBufferLength) {
channelConvBuffer = realloc(channelConvBuffer,
dataChannelLen);
channelConvBufferLength = dataChannelLen;
}
dataChannelConv = channelConvBuffer;
{
mpd_sint16 * in = (mpd_sint16 *)dataBitConv;
mpd_sint16 * out = (mpd_sint16 *)dataChannelConv;
int i, inSamples = dataBitLen >> 2;
for(i=0;i<inSamples;i++) {
*out = (*in++)/2;
*out++ += (*in++)/2;
}
}
break;
default:
ERROR("only 1 or 2 channels are supported for conversion!\n");
exit(EXIT_FAILURE);
}
}
if(inFormat->sampleRate == outFormat->sampleRate) {
@ -247,7 +270,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
}
size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
char * inBuffer, size_t inSize, AudioFormat * outFormat)
size_t inSize, AudioFormat * outFormat)
{
const int shift = sizeof(mpd_sint16);
size_t outSize = inSize;

View File

@ -37,6 +37,6 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
inSize, AudioFormat * outFormat, char * outBuffer);
size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
char * inBuffer, size_t inSize, AudioFormat * outFormat);
size_t inSize, AudioFormat * outFormat);
#endif
/* vim:set shiftwidth=8 tabstop=8 expandtab: */