added: Missing files from last commit
[xbmc:xbmc-antiquated.git] / XBMC / xbmc / cores / AudioRenderers / WaveFileRenderer.cpp
1 /*
2  *      Copyright (C) 2009 Team XBMC
3  *      http://www.xbmc.org
4  *      Portions of WAV IO based on code by Evan Merz (www.thisisnotalabel.com)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include "stdafx.h"
22 #include "WaveFileRenderer.h"
23
24
25 CWaveFileRenderer::CWaveFileRenderer() :
26   m_pOutputBuffer(NULL),
27   m_OutputBufferSize(0),
28   m_OutputBufferPos(0)
29 {
30 }
31
32 CWaveFileRenderer::~CWaveFileRenderer()
33 {
34   // Free data buffer
35   delete m_pOutputBuffer;
36
37   // Close output file
38   if (m_OutputStream.is_open())
39     m_OutputStream.close();
40 }
41
42 bool CWaveFileRenderer::Open(const char* filePath, unsigned int bufferSize, unsigned int sampleRate)
43 {
44   if(m_OutputStream.is_open())
45     return false;
46
47   // Open an output filestream
48   m_OutputStream.open(filePath, ios::out | ios::binary);
49
50   m_FileHeader.chunkId = 0x46464952; // "RIFF"  
51   m_FileHeader.chunkSize = 0x00000000; // Placeholder.  Should equal 4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
52   m_FileHeader.chunkFormat = 0x45564157 ; // "WAVE"
53   m_FileHeader.subChunk1Id = 0x20746D66 ; // "fmt "
54   m_FileHeader.subChunk1Size = 16;
55   m_FileHeader.audioFormat = 1; // PCM w/linear quantization (no compression)
56   m_FileHeader.numChannels = 2;
57   m_FileHeader.samplesPerSec = sampleRate;
58   m_FileHeader.bitsPerSample = 16;
59   m_FileHeader.bytesPerSec = m_FileHeader.samplesPerSec * m_FileHeader.numChannels * (m_FileHeader.bitsPerSample >> 3);
60   m_FileHeader.blockAlign = m_FileHeader.numChannels * (m_FileHeader.bitsPerSample >> 3);
61   m_FileHeader.subChunk2Id = 0x61746164; // "data"
62   m_FileHeader.subChunk2Size = 0x00000000; // Placeholder.  Should equal the total 'data' size (NumSamples * NumChannels * BitsPerSample/8)
63   
64   // Write the RIFF Header
65   m_OutputStream.write ((const char*)&m_FileHeader, sizeof(m_FileHeader));
66
67   // Setup output byffer
68   delete m_pOutputBuffer;
69   m_OutputBufferSize = bufferSize;
70   m_pOutputBuffer = new BYTE[m_OutputBufferSize];
71
72   return true;
73 }
74
75 unsigned int CWaveFileRenderer::GetSpace()
76 {
77   return m_OutputBufferSize - m_OutputBufferPos;
78 }
79
80 unsigned int CWaveFileRenderer::WriteData(short* pSamples, size_t len)
81 {
82   if (!m_OutputStream.is_open())
83     return 0;
84
85   if (m_OutputBufferPos + len > m_OutputBufferSize)
86     len = m_OutputBufferSize - m_OutputBufferPos;
87
88   memcpy(m_pOutputBuffer + m_OutputBufferPos, pSamples, len);
89
90   m_OutputBufferPos += len;
91   m_FileHeader.subChunk2Size += len;  // Update file header information
92   CLog::DebugLog("WaveFileRenderer: Wrote %d bytes to buffer. Buffer pos = %d, 'data' chunklen = %d.",len, m_OutputBufferPos, m_FileHeader.subChunk2Size);
93
94   return len;
95 }
96
97 // The file should be playable after this is called
98 bool CWaveFileRenderer::Save()
99 {
100   if (!m_OutputStream.is_open())
101     return false;
102
103   // Write the RIFF Header
104   UpdateHeader();
105   CLog::DebugLog("WaveFileRenderer: Saving %d bytes to file. 'data' chunklen = %d.",m_OutputBufferPos, m_FileHeader.subChunk2Size);
106
107   // Write cached data to file
108   m_OutputStream.write((const char*)m_pOutputBuffer, m_OutputBufferPos);
109
110   m_OutputBufferPos = 0;
111
112   return true;
113 }
114
115 void CWaveFileRenderer::Close(bool saveData)
116 {
117   if (!m_OutputStream.is_open())
118     return;
119     
120   if (saveData)
121     Save();
122
123   m_OutputStream.close();
124
125   m_OutputBufferSize = 0;
126   m_OutputBufferPos = 0;
127
128   delete m_pOutputBuffer;
129   m_pOutputBuffer = NULL;
130 }
131
132 // Private
133
134 void CWaveFileRenderer::UpdateHeader()
135 {
136   // Update file header
137   m_FileHeader.chunkSize = 4 + (8 + m_FileHeader.subChunk1Size) + (8 + m_FileHeader.subChunk2Size);
138
139   long pos = m_OutputStream.tellp();
140   m_OutputStream.seekp (0, ios::beg); 
141   m_OutputStream.write ((const char*)&m_FileHeader, sizeof(m_FileHeader));
142
143   m_OutputStream.seekp(pos);
144 }