00001
00002 #include "global.h"
00003 #include "MercurySoundSourceWAV.h"
00004 #include "MercuryLog.h"
00005 #include "MercurySoundDriverALSA.h"
00006
00007 MercurySoundSourceWAV::MercurySoundSourceWAV()
00008 :m_file(NULL)
00009 {
00010 }
00011
00012 MercurySoundSourceWAV::~MercurySoundSourceWAV()
00013 {
00014 if (m_playState==PLAYING)
00015 MercurySoundDriverALSA::GetInstance().RemoveSound(this);
00016 SAFE_DELETE( m_file );
00017 }
00018
00019 bool MercurySoundSourceWAV::Open(const MString& path)
00020 {
00021 RiffChunk chunk;
00022 WaveHead head;
00023 FmtChunk dataHead;
00024
00025 m_file = FILEMAN.Open( path );
00026 if (!m_file)
00027 {
00028 LOG.Warn("Could not open " + path);
00029 return false;
00030 }
00031
00032 m_file->Read(&head, sizeof(WaveHead));
00033 head.info.id = Swap32(head.info.id);
00034 TO_ENDIAN( head.info.id );
00035 head.type = Swap32(head.type);
00036 TO_ENDIAN( head.type );
00037
00038 if (head.info.id != 0x52494646)
00039 {
00040 LOG.Log(GetType() + ":" + path + " not a valid RIFF");
00041 return false;
00042 }
00043
00044 if (head.type != 0x57415645)
00045 {
00046 LOG.Log(GetType() + ":" + "Only type WAVE supported");
00047 return false;
00048 }
00049
00050 m_file->Read(&chunk, sizeof(RiffChunk));
00051 m_file->Read(&dataHead, chunk.size);
00052 chunk.id = Swap32(chunk.id);
00053 TO_ENDIAN( chunk.id );
00054
00055 if (chunk.id != 0x666D7420)
00056 {
00057 LOG.Log(GetType() + ":" + "Invalid chunk, only fmt chunks supported");
00058 return false;
00059 }
00060
00061 TO_ENDIAN2(dataHead.comp );
00062 TO_ENDIAN2(dataHead.channels );
00063 TO_ENDIAN( dataHead.srate );
00064 if (dataHead.comp != 1)
00065 {
00066 LOG.Log(GetType() + ":" + "WAV not PCM");
00067 return false;
00068 }
00069
00070 if (dataHead.channels > 2)
00071 {
00072 LOG.Log(GetType() + ":" + "Only mono or stereo is supported");
00073 return false;
00074 }
00075
00076 m_chunkSize = 0;
00077 m_chunkPosition = 0;
00078 m_atAudioChunk = false;
00079 m_destroyOnStop = false;
00080 }
00081
00082 bool MercurySoundSourceWAV::LocateAudioData()
00083 {
00084 RiffChunk chunk;
00085 while (!m_file->Eof())
00086 {
00087 char str[5];
00088 str[4] = '\0';
00089 m_file->Read(&chunk, sizeof(RiffChunk));
00090 memcpy(str, &chunk.id, 4);
00091 chunk.id = Swap32(chunk.id);
00092 TO_ENDIAN( chunk.id );
00093 TO_ENDIAN( chunk.size );
00094
00095 if (chunk.id == 0x64617461)
00096 {
00097 m_chunkSize = chunk.size;
00098 m_chunkPosition = 0;
00099 m_atAudioChunk = true;
00100 return true;
00101 }
00102 else
00103 {
00104 LOG.Info( GetType() + ":" + "Skipping unknown chunk." );
00105 m_file->Seek( m_file->Tell() + chunk.size);
00106 }
00107 }
00108 return false;
00109 }
00110
00111 float* Read(unsigned long samples);
00112
00113
00114 float* MercurySoundSourceWAV::ReadData(unsigned long samples)
00115 {
00116 if (m_chunkPosition >= m_chunkSize)
00117 m_atAudioChunk = false;
00118
00119 if (!m_atAudioChunk)
00120 LocateAudioData();
00121
00122 if (!m_atAudioChunk)
00123 {
00124 Stop();
00125 return NULL;
00126 }
00127
00128 unsigned long bytes( samples*sizeof(int16_t) );
00129 int16_t* data = new int16_t[samples];
00130 float* fdata = new float[samples];
00131
00132 memset(data, 0 , bytes);
00133 m_file->Read(data, bytes);
00134 m_chunkPosition += bytes;
00135
00136 for (unsigned int i = 0; i < samples; ++i)
00137 fdata[i] = Clamp(data[i]/32767.0f, -1.0f, 1.0f);
00138
00139 delete data;
00140 return fdata;
00141 }
00142
00143 bool MercurySoundSourceWAV::Play()
00144 {
00145 if (m_playState == PLAYING)
00146 {
00147 LOG.Info(GetType() + ":" + "Streamed sound already playing");
00148 return false;
00149 }
00150 m_playState = PLAYING;
00151 MercurySoundDriverALSA::GetInstance().AddSound(this);
00152 return true;
00153 }
00154
00155 bool MercurySoundSourceWAV::Stop()
00156 {
00157 m_playState = STOPPED;
00158 MercurySoundDriverALSA::GetInstance().RemoveSound(this);
00159 if (m_destroyOnStop)
00160 delete this;
00161 }
00162 void MercurySoundSourceWAV::Pause(bool pause)
00163 {
00164 if ( (m_playState==PLAYING)&&pause )
00165 m_playState = PAUSED;
00166 else if ((m_playState==PAUSED)&&!pause)
00167 m_playState = PLAYING;
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196