|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2005 by Olivier Goffart *
|
|
|
|
* ogoffart@kde.org *
|
|
|
|
* *
|
|
|
|
* 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., *
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "sound.h"
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqdatastream.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Sound::Sound()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Sound::~Sound()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define READ_FROM_STREAM(FORMAT,NAME) FORMAT NAME; stream >> NAME;
|
|
|
|
#define MAGIC(CH) { \
|
|
|
|
stream >> magic; \
|
|
|
|
if( magic != ( (CH)[0] | (CH)[1]<<8 | (CH)[2]<< 16 | (CH)[3] << 24 ) ) \
|
|
|
|
{ \
|
|
|
|
kdWarning() << k_funcinfo << "bad format " << magic << " != " << CH "\n";\
|
|
|
|
return;\
|
|
|
|
} }
|
|
|
|
|
|
|
|
#define ABS(X) ( (X>0) ? X : -X )
|
|
|
|
|
|
|
|
void Sound::load(const TQString& filename)
|
|
|
|
{
|
|
|
|
kdDebug() << k_funcinfo << filename << endl;
|
|
|
|
data=TQMemArray<TQ_INT32>();
|
|
|
|
TQFile file(filename);
|
|
|
|
if(!file.open(IO_ReadOnly))
|
|
|
|
{
|
|
|
|
kdWarning() << k_funcinfo <<"unable to open file" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TQDataStream stream(&file);
|
|
|
|
stream.setByteOrder( TQDataStream::LittleEndian );
|
|
|
|
TQ_INT32 magic;
|
|
|
|
|
|
|
|
MAGIC("RIFF");
|
|
|
|
READ_FROM_STREAM(TQ_UINT32,ChunkSize);
|
|
|
|
MAGIC("WAVE");
|
|
|
|
MAGIC("fmt ");
|
|
|
|
READ_FROM_STREAM(TQ_UINT32,ChunkSize2);
|
|
|
|
READ_FROM_STREAM(TQ_INT16,AudioFormat);
|
|
|
|
READ_FROM_STREAM(TQ_UINT16,NumberOfChannels);
|
|
|
|
READ_FROM_STREAM(TQ_UINT32,SampleRate);
|
|
|
|
_fs=SampleRate;
|
|
|
|
READ_FROM_STREAM(TQ_UINT32,ByteRate);
|
|
|
|
READ_FROM_STREAM(TQ_UINT16,BlockAlign);
|
|
|
|
READ_FROM_STREAM(TQ_UINT16,BitsPerSample);
|
|
|
|
MAGIC("data");
|
|
|
|
READ_FROM_STREAM(TQByteArray,SoundData);
|
|
|
|
NumberOfChannels=1; //Wav i play are broken
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
uint BytePS=BitsPerSample/8;
|
|
|
|
uint NumberOfSamples = (SoundData.size())/(NumberOfChannels*BytePS);
|
|
|
|
|
|
|
|
|
|
|
|
data.resize(NumberOfSamples);
|
|
|
|
|
|
|
|
// kdDebug() << k_funcinfo << NumberOfSamples << " samples" << endl;
|
|
|
|
|
|
|
|
max=0;
|
|
|
|
for(unsigned long int f=0;f<NumberOfSamples;f++)
|
|
|
|
{
|
|
|
|
TQ_INT32 nb=0;
|
|
|
|
for(uint k=0;k<BytePS;k++)
|
|
|
|
{
|
|
|
|
nb |= (SoundData.tqat(f*BytePS+k)&0x000000FF) << (k*8);
|
|
|
|
}
|
|
|
|
if(nb & (1 << (BytePS*8 -1)) )
|
|
|
|
nb = nb-(1<<BytePS*8);
|
|
|
|
data[f]=nb;
|
|
|
|
if(ABS(nb)>max)
|
|
|
|
{
|
|
|
|
max=ABS(nb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static int q=0;
|
|
|
|
TQString name="test" + TQString::number(q++) + ".wav";
|
|
|
|
save(name);*/
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SMAGIC(CH) { stream << ( TQ_INT32) ( (CH)[0] | (CH)[1]<<8 | (CH)[2]<< 16 | (CH)[3] << 24 ) ; }
|
|
|
|
|
|
|
|
void Sound::save(const TQString& filename) const
|
|
|
|
{
|
|
|
|
kdDebug( 1217 ) << k_funcinfo << filename << " - " << data.size() << endl;
|
|
|
|
TQFile file(filename);
|
|
|
|
if(!file.open(IO_WriteOnly))
|
|
|
|
{
|
|
|
|
kdWarning() << k_funcinfo <<"unable to open file" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TQDataStream stream(&file);
|
|
|
|
stream.setByteOrder( TQDataStream::LittleEndian );
|
|
|
|
|
|
|
|
|
|
|
|
TQByteArray SoundData(data.size()*2);
|
|
|
|
|
|
|
|
for(unsigned long int f=0;f<data.size();f++)
|
|
|
|
{
|
|
|
|
TQ_UINT16 val= (signed short int) ( (data.tqat(f) * ((double)(1<<13)/(signed)max) ) );
|
|
|
|
SoundData.tqat( 2*f )= val & 0x00FF;
|
|
|
|
SoundData.tqat(2*f+1)= (val & 0xFF00) >> 8;
|
|
|
|
|
|
|
|
// kdDebug( 1217 ) << k_funcinfo << data.tqat(f) << " / " << max << " = " << val << " | " << SoundData[ 2*f ] << " "<< SoundData[ 2*f+1 ] << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_UINT16 NumberOfChannels=2;
|
|
|
|
TQ_UINT32 SampleRate=_fs;
|
|
|
|
|
|
|
|
SMAGIC("RIFF");
|
|
|
|
//READ_FROM_STREAM(TQ_UINT32,ChunkSize);
|
|
|
|
stream << (TQ_UINT32)(36+ SoundData.size());
|
|
|
|
SMAGIC("WAVE");
|
|
|
|
SMAGIC("fmt ");
|
|
|
|
//READ_FROM_STREAM(TQ_UINT32,ChunkSize2);
|
|
|
|
stream << (TQ_UINT32)(16);
|
|
|
|
//READ_FROM_STREAM(TQ_INT16,AudioFormat);
|
|
|
|
stream << (TQ_INT16)(1);
|
|
|
|
//READ_FROM_STREAM(TQ_UINT16,NumberOfChannels);
|
|
|
|
stream << (TQ_UINT16)(NumberOfChannels);
|
|
|
|
//READ_FROM_STREAM(TQ_UINT32,SampleRate);
|
|
|
|
stream << (TQ_UINT32)(SampleRate);
|
|
|
|
//READ_FROM_STREAM(TQ_UINT32,ByteRate);
|
|
|
|
stream << (TQ_UINT32)(NumberOfChannels*SampleRate*16/8);
|
|
|
|
//READ_FROM_STREAM(TQ_UINT16,BlockAlign);
|
|
|
|
stream << (TQ_UINT16)(16/8 *NumberOfChannels);
|
|
|
|
//READ_FROM_STREAM(TQ_UINT16,BitsPerSample);
|
|
|
|
stream << (TQ_UINT16)(16);
|
|
|
|
SMAGIC("data");
|
|
|
|
//READ_FROM_STREAM(TQByteArray,SoundData);
|
|
|
|
stream << SoundData;
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
void Sound::load(const TQString& filename)
|
|
|
|
{
|
|
|
|
cout << "saout \n";
|
|
|
|
data=TQMemArray<long unsigned int>();
|
|
|
|
static const int BUFFER_LEN = 4096;
|
|
|
|
|
|
|
|
//code from libtunepimp
|
|
|
|
//(wav_trm.cpp)
|
|
|
|
|
|
|
|
FILE *source;
|
|
|
|
unsigned char buffer[100], *copyBuffer;
|
|
|
|
unsigned int bytes;
|
|
|
|
unsigned long ulRIFF;
|
|
|
|
unsigned long ulLength;
|
|
|
|
unsigned long ulWAVE;
|
|
|
|
unsigned long ulType;
|
|
|
|
unsigned long ulCount;
|
|
|
|
unsigned long ulLimit;
|
|
|
|
bool haveWaveHeader = false;
|
|
|
|
unsigned long waveSize = 0;
|
|
|
|
WAVEFORMAT waveFormat;
|
|
|
|
int toRead;
|
|
|
|
mb_int64_t fileLen = 0;
|
|
|
|
|
|
|
|
source = fopen(filename.ascii(), "rb");
|
|
|
|
if (source == NULL)
|
|
|
|
{
|
|
|
|
// errorString = string("File not found");
|
|
|
|
// fclose(source);
|
|
|
|
cout << "File not found \n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fseek(source, 0, SEEK_END);
|
|
|
|
fileLen = ftell(source);
|
|
|
|
fseek(source, 0, SEEK_SET);
|
|
|
|
|
|
|
|
if (fread(buffer, 1, 12, source) != 12)
|
|
|
|
{
|
|
|
|
// errorString = string("File is too short");
|
|
|
|
cout << "File is to short \n";
|
|
|
|
fclose(source);
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
ulRIFF = (unsigned long)(((unsigned long *)buffer)[0]);
|
|
|
|
ulLength = (unsigned long)(((unsigned long *)buffer)[1]);
|
|
|
|
ulWAVE = (unsigned long)(((unsigned long *)buffer)[2]);
|
|
|
|
|
|
|
|
if(ulRIFF != MAKEFOURCC('R', 'I', 'F', 'F') ||
|
|
|
|
ulWAVE != MAKEFOURCC('W', 'A', 'V', 'E'))
|
|
|
|
{
|
|
|
|
// errorString = strdup("File is not in WAVE format");
|
|
|
|
cout << "File is not WAVE \n";
|
|
|
|
fclose(source);
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run through the bytes looking for the tags
|
|
|
|
ulCount = 0;
|
|
|
|
ulLimit = ulLength - 4;
|
|
|
|
while (ulCount < ulLimit && waveSize == 0)
|
|
|
|
{
|
|
|
|
if (fread(buffer, 1, 8, source) != 8)
|
|
|
|
{
|
|
|
|
// errorString = strdup("File is too short");
|
|
|
|
cout << "File is to short \n";
|
|
|
|
fclose(source);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ulType = (unsigned long)(((unsigned long *)buffer)[0]);
|
|
|
|
ulLength = (unsigned long)(((unsigned long *)buffer)[1]);
|
|
|
|
switch (ulType)
|
|
|
|
{
|
|
|
|
// format
|
|
|
|
case MAKEFOURCC('f', 'm', 't', ' '):
|
|
|
|
if (ulLength < sizeof(WAVEFORMAT))
|
|
|
|
{
|
|
|
|
// errorString = strdup("File is too short");
|
|
|
|
cout << "File is to short \n";
|
|
|
|
fclose(source);
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fread(&waveFormat, 1, ulLength, source) != ulLength)
|
|
|
|
{
|
|
|
|
// errorString = strdup("File is too short");
|
|
|
|
cout << "File is to short \n";
|
|
|
|
fclose(source);
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (waveFormat.wFormatTag != WAVE_FORMAT_PCM)
|
|
|
|
{
|
|
|
|
// errorString = strdup("Unsupported WAV format");
|
|
|
|
cout << "Unsupported WAVE \n";
|
|
|
|
fclose(source);
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
haveWaveHeader = true;
|
|
|
|
|
|
|
|
ulCount += ulLength;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// data
|
|
|
|
case MAKEFOURCC('d', 'a', 't', 'a'):
|
|
|
|
waveSize = ulLength;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fseek(source, ulLength, SEEK_CUR);
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!haveWaveHeader)
|
|
|
|
{
|
|
|
|
// errorString = strdup("Could not find WAV header");
|
|
|
|
cout << "Header nbot found \n";
|
|
|
|
fclose(source);
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
fileLen -= (mb_int64_t)ftell(source);
|
|
|
|
fileLen /= waveFormat.nChannels;
|
|
|
|
fileLen /= (waveFormat.nBlockAlign / waveFormat.nChannels);
|
|
|
|
|
|
|
|
fileLen /= waveFormat.nSamplesPerSec;
|
|
|
|
|
|
|
|
//on ne lit qu'un channel
|
|
|
|
//waveSize=fileLen;
|
|
|
|
data.resize(waveSize);
|
|
|
|
unsigned long pos=0;
|
|
|
|
|
|
|
|
cout << "Weeee "<< waveSize <<"\n";
|
|
|
|
|
|
|
|
copyBuffer = (unsigned char*)malloc(BUFFER_LEN);
|
|
|
|
if (copyBuffer == NULL)
|
|
|
|
{
|
|
|
|
// errorString = strdup("Cannot allocate buffer space.");
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
toRead = min(waveSize, (unsigned long)BUFFER_LEN);
|
|
|
|
if (toRead <= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
bytes = fread(copyBuffer, 1, toRead, source);
|
|
|
|
if (bytes <= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
for(uint f=0;f<bytes;f+=4)
|
|
|
|
{
|
|
|
|
data[pos]=(((unsigned long*)copyBuffer)[f/4]);
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
|
|
|
|
waveSize -= toRead;
|
|
|
|
}
|
|
|
|
free(copyBuffer);
|
|
|
|
fclose(source);
|
|
|
|
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|