mirror of
https://github.com/tuxbox-neutrino/neutrino.git
synced 2025-09-02 02:11:11 +02:00
our current experimental Neutrino branch
git-svn-id: file:///home/bas/coolstream_public_svn/THIRDPARTY/applications/neutrino-experimental@27 e54a6e83-5905-42d5-8d5c-058d10e6a962
This commit is contained in:
213
src/driver/audiodec/wavdec.cpp
Normal file
213
src/driver/audiodec/wavdec.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
Neutrino-GUI - DBoxII-Project
|
||||
|
||||
Copyright (C) 2004 Zwen
|
||||
|
||||
Homepage: http://www.dbox2.info/
|
||||
|
||||
Kommentar:
|
||||
|
||||
wav audio decoder
|
||||
|
||||
License: GPL
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <wavdec.h>
|
||||
#include <sstream>
|
||||
#include <driver/audioplay.h>
|
||||
#include <linux/soundcard.h>
|
||||
|
||||
#define ProgName "WavDec"
|
||||
// nr of msecs to skip in ff/rev mode
|
||||
#define MSECS_TO_SKIP 3000
|
||||
// nr of msecs to play in ff/rev mode
|
||||
#define MSECS_TO_PLAY 200
|
||||
|
||||
struct WavHeader
|
||||
{
|
||||
char ChunkID[4];
|
||||
int ChunkSize;
|
||||
char Format[4];
|
||||
char Subchunk1ID[4];
|
||||
int Subchunk1Size;
|
||||
short AudioFormat;
|
||||
short NumChannels;
|
||||
int SampleRate;
|
||||
int ByteRate;
|
||||
short BlockAlign;
|
||||
short BitsPerSample;
|
||||
char Subchunk2ID[4];
|
||||
int Subchunk2Size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
int endianTest=1;
|
||||
#define Swap32IfBE(l) \
|
||||
(*(char *)&endianTest ? (l) : \
|
||||
((((l) & 0xff000000) >> 24) | \
|
||||
(((l) & 0x00ff0000) >> 8) | \
|
||||
(((l) & 0x0000ff00) << 8) | \
|
||||
(((l) & 0x000000ff) << 24)))
|
||||
#define Swap16IfBE(l) \
|
||||
(*(char *)&endianTest ? (l) : \
|
||||
((((l) & 0xff00) >> 8) | \
|
||||
(((l) & 0x00ff) << 8)))
|
||||
|
||||
#define MAX_OUTPUT_SAMPLES 1022 /* AVIA_GT_PCM_MAX_SAMPLES-1 */
|
||||
|
||||
CBaseDec::RetCode CWavDec::Decoder(FILE *in, int OutputFd, State* state, CAudioMetaData* meta_data, time_t* time_played, unsigned int* secondsToSkip)
|
||||
{
|
||||
char* buffer;
|
||||
RetCode Status=OK;
|
||||
|
||||
if (!SetMetaData(in, meta_data))
|
||||
{
|
||||
Status=DATA_ERR;
|
||||
return Status;
|
||||
}
|
||||
fseek(in, header_size, SEEK_SET);
|
||||
int fmt;
|
||||
switch(mBitsPerSample)
|
||||
{
|
||||
case 8 : fmt = AFMT_U8;
|
||||
break;
|
||||
case 16 : fmt = header_size == 0 ? AFMT_S16_BE : AFMT_S16_LE;
|
||||
break;
|
||||
default:
|
||||
printf("%s: wrong bits per sample (%d)\n", ProgName, mBitsPerSample);
|
||||
Status=DATA_ERR;
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (SetDSP(OutputFd, fmt, meta_data->samplerate , mChannels))
|
||||
{
|
||||
Status=DSPSET_ERR;
|
||||
return Status;
|
||||
}
|
||||
int actSecsToSkip = (*secondsToSkip != 0) ? *secondsToSkip : MSECS_TO_SKIP / 1000;
|
||||
unsigned int oldSecsToSkip = *secondsToSkip;
|
||||
int jumppos=0;
|
||||
int bytes;
|
||||
int bytes_to_play = (int) (1.0 * MSECS_TO_PLAY / 1000 * meta_data->bitrate / 8);
|
||||
int bytes_to_skip = (int) (1.0 * actSecsToSkip * meta_data->bitrate / 8);
|
||||
int buffersize = MAX_OUTPUT_SAMPLES * mChannels * mBitsPerSample / 8;
|
||||
buffer = (char*) malloc (buffersize);
|
||||
do
|
||||
{
|
||||
while(*state==PAUSE)
|
||||
usleep(10000);
|
||||
|
||||
if(*state==FF || *state==REV)
|
||||
{
|
||||
if (oldSecsToSkip != *secondsToSkip)
|
||||
{
|
||||
actSecsToSkip = (*secondsToSkip != 0) ? *secondsToSkip : MSECS_TO_SKIP / 1000;
|
||||
bytes_to_skip = (int) (1.0 * actSecsToSkip * meta_data->bitrate / 8);
|
||||
oldSecsToSkip = *secondsToSkip;
|
||||
}
|
||||
//printf("skipping %d secs and %d bytes\n",actSecsToSkip,bytes_to_skip);
|
||||
if(std::abs(ftell(in)-jumppos) > bytes_to_play)
|
||||
{
|
||||
if(*state==FF)
|
||||
{
|
||||
fseek(in, bytes_to_skip, SEEK_CUR);
|
||||
jumppos=ftell(in);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ftell(in) < bytes_to_skip)
|
||||
{
|
||||
fseek(in, header_size, SEEK_SET);
|
||||
*state=PLAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
fseek(in, -bytes_to_skip, SEEK_CUR);
|
||||
jumppos=ftell(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if a custom value was set we only jump once
|
||||
if (*secondsToSkip != 0) {
|
||||
*state=PLAY;
|
||||
}
|
||||
}
|
||||
|
||||
bytes = fread(buffer, 1, buffersize, in);
|
||||
if (write(OutputFd, buffer, bytes) != bytes)
|
||||
{
|
||||
fprintf(stderr,"%s: PCM write error (%s).\n", ProgName, strerror(errno));
|
||||
Status=WRITE_ERR;
|
||||
}
|
||||
*time_played = (meta_data->bitrate!=0) ? (ftell(in)-header_size)*8/meta_data->bitrate : 0;
|
||||
} while (bytes > 0 && *state!=STOP_REQ && Status==OK);
|
||||
free(buffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
bool CWavDec::GetMetaData(FILE *in, const bool nice, CAudioMetaData* m)
|
||||
{
|
||||
return SetMetaData(in, m);
|
||||
}
|
||||
|
||||
CWavDec* CWavDec::getInstance()
|
||||
{
|
||||
static CWavDec* WavDec = NULL;
|
||||
if(WavDec == NULL)
|
||||
{
|
||||
WavDec = new CWavDec();
|
||||
}
|
||||
return WavDec;
|
||||
}
|
||||
|
||||
bool CWavDec::SetMetaData(FILE* in, CAudioMetaData* m)
|
||||
{
|
||||
/* Set Metadata */
|
||||
struct WavHeader wh;
|
||||
|
||||
header_size = 44;
|
||||
|
||||
fseek(in, 0, SEEK_END);
|
||||
int filesize = ftell(in);
|
||||
fseek(in, 0, SEEK_SET);
|
||||
if(fread(&wh, sizeof(wh), 1, in)!=1)
|
||||
return false;
|
||||
if(memcmp(wh.ChunkID, "RIFF", 4)!=0 ||
|
||||
memcmp(wh.Format, "WAVE", 4)!=0 ||
|
||||
Swap16IfBE(wh.AudioFormat) != 1)
|
||||
{
|
||||
printf("%s: wrong format (header)\n", ProgName);
|
||||
return false;
|
||||
}
|
||||
m->type = CAudioMetaData::WAV;
|
||||
m->bitrate = Swap32IfBE(wh.ByteRate)*8;
|
||||
m->samplerate = Swap32IfBE(wh.SampleRate);
|
||||
mBitsPerSample = Swap16IfBE(wh.BitsPerSample);
|
||||
mChannels = Swap16IfBE(wh.NumChannels);
|
||||
m->total_time = (m->bitrate!=0) ? (filesize-header_size)*8 / m->bitrate : 0;
|
||||
std::stringstream ss;
|
||||
ss << "Riff/Wave / " << mChannels << "channel(s) / " << mBitsPerSample << "bit";
|
||||
m->type_info = ss.str();
|
||||
m->changed=true;
|
||||
return true;
|
||||
}
|
Reference in New Issue
Block a user