2 * Copyright (C) 2005-2008 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "AudioDecoder.h"
23 #include "CodecFactory.h"
24 #include "GUISettings.h"
26 #include "MusicInfoTag.h"
27 #include "utils/SingleLock.h"
28 #include "utils/log.h"
31 #define INTERNAL_BUFFER_LENGTH sizeof(float)*2*44100 // float samples, 2 channels, 44100 samples per sec = 1 second
33 CAudioDecoder::CAudioDecoder()
39 m_status = STATUS_NO_FILE;
42 m_gaplessBufferSize = 0;
46 CAudioDecoder::~CAudioDecoder()
51 void CAudioDecoder::Destroy()
53 CSingleLock lock(m_critSection);
54 m_status = STATUS_NO_FILE;
56 m_pcmBuffer.Destroy();
57 m_gaplessBufferSize = 0;
66 bool CAudioDecoder::Create(const CFileItem &file, __int64 seekOffset, unsigned int nBufferSize)
70 CSingleLock lock(m_critSection);
71 // create our pcm buffer
72 m_pcmBuffer.Create((int)std::max<unsigned int>(2, nBufferSize) *
73 INTERNAL_BUFFER_LENGTH);
75 // reset our playback timing variables
78 // get correct cache size
79 unsigned int filecache = g_guiSettings.GetInt("cacheaudio.internet");
81 filecache = g_guiSettings.GetInt("cache.harddisk");
82 else if ( file.IsOnDVD() )
83 filecache = g_guiSettings.GetInt("cacheaudio.dvdrom");
84 else if ( file.IsOnLAN() )
85 filecache = g_guiSettings.GetInt("cacheaudio.lan");
88 m_codec=CodecFactory::CreateCodecDemux(file.m_strPath, file.GetMimeType(), filecache * 1024);
90 if (!m_codec || !m_codec->Init(file.m_strPath, filecache * 1024))
92 CLog::Log(LOGERROR, "CAudioDecoder: Unable to Init Codec while loading file %s", file.m_strPath.c_str());
96 m_blockSize = m_codec->m_Channels * m_codec->m_BitsPerSample / 8;
98 // set total time from the given tag
99 if (file.HasMusicInfoTag() && file.GetMusicInfoTag()->GetDuration())
100 m_codec->SetTotalTime(file.GetMusicInfoTag()->GetDuration());
103 m_codec->Seek(seekOffset);
105 m_status = STATUS_QUEUING;
110 void CAudioDecoder::GetDataFormat(unsigned int *channels, unsigned int *samplerate, unsigned int *bitspersample)
115 if (channels) *channels = m_codec->m_Channels;
116 if (samplerate) *samplerate = m_codec->m_SampleRate;
117 if (bitspersample) *bitspersample = m_codec->m_BitsPerSample;
120 __int64 CAudioDecoder::Seek(__int64 time)
125 if (time < 0) time = 0;
126 if (time > m_codec->m_TotalTime) time = m_codec->m_TotalTime;
127 return m_codec->Seek(time);
130 __int64 CAudioDecoder::TotalTime()
133 return m_codec->m_TotalTime;
137 unsigned int CAudioDecoder::GetDataSize()
139 if (m_status == STATUS_QUEUING || m_status == STATUS_NO_FILE)
141 // check for end of file and end of buffer
142 if (m_status == STATUS_ENDING && m_pcmBuffer.getMaxReadSize() < PACKET_SIZE)
143 m_status = STATUS_ENDED;
144 return m_pcmBuffer.getMaxReadSize() / sizeof(float);
147 void *CAudioDecoder::GetData(unsigned int size)
149 if (size > OUTPUT_SAMPLES)
151 CLog::Log(LOGWARNING, "CAudioDecoder::GetData() more bytes/samples (%i) requested than we have to give (%i)!", size, OUTPUT_SAMPLES);
152 size = OUTPUT_SAMPLES;
154 // first copy anything from our gapless buffer
155 if (m_gaplessBufferSize > size)
157 memcpy(m_outputBuffer, m_gaplessBuffer, size*sizeof(float));
158 memmove(m_gaplessBuffer, m_gaplessBuffer + size, (m_gaplessBufferSize - size)*sizeof(float));
159 m_gaplessBufferSize -= size;
160 return m_outputBuffer;
162 if (m_gaplessBufferSize)
163 memcpy(m_outputBuffer, m_gaplessBuffer, m_gaplessBufferSize*sizeof(float));
165 if (m_pcmBuffer.ReadData( (char *)(m_outputBuffer + m_gaplessBufferSize), (size - m_gaplessBufferSize) * sizeof(float)))
167 m_gaplessBufferSize = 0;
168 // check for end of file + end of buffer
169 if ( m_status == STATUS_ENDING && m_pcmBuffer.getMaxReadSize() < (int) (OUTPUT_SAMPLES * sizeof(float)))
171 CLog::Log(LOGINFO, "CAudioDecoder::GetData() ending track - only have %lu samples left", (unsigned long)(m_pcmBuffer.getMaxReadSize() / sizeof(float)));
172 m_status = STATUS_ENDED;
174 return m_outputBuffer;
176 CLog::Log(LOGERROR, "CAudioDecoder::GetData() ReadBinary failed with %i samples", size - m_gaplessBufferSize);
180 void CAudioDecoder::PrefixData(void *data, unsigned int size)
184 CLog::Log(LOGERROR, "CAudioDecoder::PrefixData() failed - null data pointer");
187 m_gaplessBufferSize = std::min<unsigned int>(PACKET_SIZE, size);
188 memcpy(m_gaplessBuffer, data, m_gaplessBufferSize*sizeof(float));
189 if (m_gaplessBufferSize != size)
190 CLog::Log(LOGWARNING, "CAudioDecoder::PrefixData - losing %i bytes of audio data in track transistion", size - m_gaplessBufferSize);
193 int CAudioDecoder::ReadSamples(int numsamples)
195 if (m_status == STATUS_NO_FILE || m_status == STATUS_ENDING || m_status == STATUS_ENDED)
196 return RET_SLEEP; // nothing loaded yet
198 // start playing once we're fully queued and we're ready to go
199 if (m_status == STATUS_QUEUED && m_canPlay)
200 m_status = STATUS_PLAYING;
202 // grab a lock to ensure the codec is created at this point.
203 CSingleLock lock(m_critSection);
206 int maxsize = std::min<int>(INPUT_SAMPLES,
207 (m_pcmBuffer.getMaxWriteSize() / (int)(sizeof (float))));
208 numsamples = std::min<int>(numsamples, maxsize);
209 numsamples -= (numsamples % m_codec->m_Channels); // make sure it's divisible by our number of channels
212 int actualsamples = 0;
213 // if our codec sends floating point, then read it
214 int result = READ_ERROR;
215 if (m_codec->HasFloatData())
216 result = m_codec->ReadSamples(m_inputBuffer, numsamples, &actualsamples);
218 result = ReadPCMSamples(m_inputBuffer, numsamples, &actualsamples);
220 if ( result != READ_ERROR && actualsamples )
222 // do any post processing of the audio (eg replaygain etc.)
223 ProcessAudio(m_inputBuffer, actualsamples);
225 // move it into our buffer
226 m_pcmBuffer.WriteData((char *)m_inputBuffer, actualsamples * sizeof(float));
229 if (m_status == STATUS_QUEUING && m_pcmBuffer.getMaxReadSize() > m_pcmBuffer.getSize() * 0.9)
231 CLog::Log(LOGINFO, "AudioDecoder: File is queued");
232 m_status = STATUS_QUEUED;
235 if (result == READ_EOF) // EOF reached
237 // setup ending if we're within set time of the end (currently just EOF)
239 if (m_status < STATUS_ENDING)
240 m_status = STATUS_ENDING;
245 if (result == READ_ERROR)
247 // error decoding, lets finish up and get out
248 CLog::Log(LOGERROR, "CAudioDecoder: Error while decoding %i", result);
251 if (result == READ_EOF)
254 // setup ending if we're within set time of the end (currently just EOF)
255 if (m_status < STATUS_ENDING)
256 m_status = STATUS_ENDING;
259 return RET_SLEEP; // nothing to do
262 void CAudioDecoder::ProcessAudio(float *data, int numsamples)
264 if (g_guiSettings.m_replayGain.iType != REPLAY_GAIN_NONE)
266 float gainFactor = GetReplayGain();
267 for (int i = 0; i < numsamples; i++)
269 data[i] *= gainFactor;
270 // check the range (is this needed here?)
271 if (data[i] > 1.0f) data[i] = 1.0f;
272 if (data[i] < -1.0f) data[i] = -1.0f;
277 float CAudioDecoder::GetReplayGain()
279 #define REPLAY_GAIN_DEFAULT_LEVEL 89.0f
280 // Compute amount of gain
281 float replaydB = (float)g_guiSettings.m_replayGain.iNoGainPreAmp;
283 if (g_guiSettings.m_replayGain.iType == REPLAY_GAIN_ALBUM)
285 if (m_codec->m_replayGain.iHasGainInfo & REPLAY_GAIN_HAS_ALBUM_INFO)
287 replaydB = (float)g_guiSettings.m_replayGain.iPreAmp + (float)m_codec->m_replayGain.iAlbumGain / 100.0f;
288 peak = m_codec->m_replayGain.fAlbumPeak;
290 else if (m_codec->m_replayGain.iHasGainInfo & REPLAY_GAIN_HAS_TRACK_INFO)
292 replaydB = (float)g_guiSettings.m_replayGain.iPreAmp + (float)m_codec->m_replayGain.iTrackGain / 100.0f;
293 peak = m_codec->m_replayGain.fTrackPeak;
296 else if (g_guiSettings.m_replayGain.iType == REPLAY_GAIN_TRACK)
298 if (m_codec->m_replayGain.iHasGainInfo & REPLAY_GAIN_HAS_TRACK_INFO)
300 replaydB = (float)g_guiSettings.m_replayGain.iPreAmp + (float)m_codec->m_replayGain.iTrackGain / 100.0f;
301 peak = m_codec->m_replayGain.fTrackPeak;
303 else if (m_codec->m_replayGain.iHasGainInfo & REPLAY_GAIN_HAS_ALBUM_INFO)
305 replaydB = (float)g_guiSettings.m_replayGain.iPreAmp + (float)m_codec->m_replayGain.iAlbumGain / 100.0f;
306 peak = m_codec->m_replayGain.fAlbumPeak;
309 // convert to a gain type
310 float replaygain = pow(10.0f, (replaydB - REPLAY_GAIN_DEFAULT_LEVEL)* 0.05f);
312 if (g_guiSettings.m_replayGain.bAvoidClipping)
314 if (fabs(peak * replaygain) > 1.0f)
315 replaygain = 1.0f / fabs(peak);
320 int CAudioDecoder::ReadPCMSamples(float *buffer, int numsamples, int *actualsamples)
322 // convert samples to bytes
323 numsamples *= (m_codec->m_BitsPerSample / 8);
325 // read in our PCM data
326 int result = m_codec->ReadPCM(m_pcmInputBuffer, numsamples, actualsamples);
328 // convert to floats (-1 ... 1) range
330 switch (m_codec->m_BitsPerSample)
333 for (i = 0; i < *actualsamples; i++)
334 m_inputBuffer[i] = 1.0f / 0x7f * (m_pcmInputBuffer[i] - 128);
338 for (i = 0; i < *actualsamples; i++)
339 m_inputBuffer[i] = 1.0f / 0x7fff * ((short *)m_pcmInputBuffer)[i];
343 for (i = 0; i < *actualsamples; i++)
344 m_inputBuffer[i] = 1.0f / 0x7fffff * (((int)m_pcmInputBuffer[3*i] << 0) | ((int)m_pcmInputBuffer[3*i+1] << 8) | (((int)((char *)m_pcmInputBuffer)[3*i+2]) << 16));