2 ==============================================================================
\r
4 This file is part of the async
\r
5 Copyright 2005-11 by Satoshi Fujiwara.
\r
7 async can be redistributed and/or modified under the terms of the
\r
8 GNU General Public License, as published by the Free Software Foundation;
\r
9 either version 2 of the License, or (at your option) any later version.
\r
11 async is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with async; if not, visit www.gnu.org/licenses or write to the
\r
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330,
\r
19 Boston, MA 02111-1307 USA
\r
21 ==============================================================================
\r
24 // SDK
\82Ì
\83T
\83\93\83v
\83\8b\82ð
\89ü
\91¢
\82µ
\82½
\8dì
\82Á
\82½
\82à
\82Ì
\81B
\93à
\97e
\82Í
\82Ù
\82Ú
\82»
\82Ì
\82Ü
\82Ü
\82¾
\82ª
\81A
\94ñ
\93¯
\8aú
\93Ç
\82Ý
\8d\9e\82Ý
\82É
\r
25 //
\91Î
\89\9e\82³
\82¹
\82½
\81B
\r
29 #define _CRTDBG_MAP_ALLOC
\r
31 #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
\r
38 #include <ksmedia.h>
\r
40 #include "async_reader.h"
\r
41 using namespace std;
\r
47 ULONG Riff4CC; // "RIFF" 4-character code
\r
48 ULONG FileSize; // total file size in bytes
\r
49 ULONG Wave4CC; // "WAVE" 4-character code
\r
50 ULONG Fmt4CC; // "fmt " 4-character code
\r
51 ULONG FormatSize; // wave format size in bytes
\r
60 // Any file smaller than this cannot possibly contain wave data.
\r
61 #define MIN_WAVE_FILE_SIZE (sizeof(FileHeader)+sizeof(PCMWAVEFORMAT)+sizeof(ChunkHeader)+1)
\r
63 // Macro to build FOURCC from first four characters in ASCII string
\r
64 #define FOURCC(s) ((ULONG)(s[0] | (s[1]<<8) | (s[2]<<16) | (s[3]<<24)))
\r
67 // Constructor -- Open wave file and parse file header.
\r
69 async_reader::async_reader(const std::wstring file_name, bool repeat_mode)
\r
71 stream_status_(false),
\r
72 data_chunk_position(0),
\r
73 total_data_bytes_(0),
\r
74 data_bytes_remaining_(0),
\r
76 reader_repeat_mode_(repeat_mode),
\r
77 async_reading_(false)
\r
80 //
\83C
\83x
\83\93\83g
\83I
\83u
\83W
\83F
\83N
\83g
\82Ì
\8f\89\8aú
\89»
\r
81 ZeroMemory(&wfx_, sizeof(wfx_));
\r
82 event_.reset(::CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_MODIFY_STATE | SYNCHRONIZE));
\r
84 // OVERLAPPED
\8d\
\91¢
\91Ì
\82Ì
\8f\89\8aú
\89»
\r
85 ZeroMemory(&overlapped_,sizeof(overlapped_));
\r
86 overlapped_.hEvent = event_.get();
\r
90 //
\83t
\83@
\83C
\83\8b\83I
\81[
\83v
\83\93\r
91 file_.reset(CreateFile(file_name.c_str(),GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY | FILE_FLAG_OVERLAPPED,NULL));
\r
92 if(file_.get() == INVALID_HANDLE_VALUE)
\r
94 throw win32_error_exception(GetLastError());
\r
97 //
\83t
\83@
\83C
\83\8b\83w
\83b
\83_
\82Ì
\93Ç
\82Ý
\8d\9e\82Ý
\r
99 read_data_sync(reinterpret_cast<BYTE*>(&fileHdr),sizeof(fileHdr));
\r
101 //
\83w
\83b
\83_
\82Ì
\83`
\83F
\83b
\83N
\r
102 if (fileHdr.Riff4CC != FOURCC("RIFF") ||
\r
103 fileHdr.FileSize < MIN_WAVE_FILE_SIZE ||
\r
104 fileHdr.Wave4CC != FOURCC("WAVE") ||
\r
105 fileHdr.Fmt4CC != FOURCC("fmt ") ||
\r
106 fileHdr.FormatSize < sizeof(PCMWAVEFORMAT))
\r
108 throw file_error_exception(std::wstring(L"
\95s
\96¾
\82È.WAV
\83t
\83@
\83C
\83\8b\83t
\83H
\81[
\83}
\83b
\83g
\82Å
\82·
\81B"));
\r
111 //
\83t
\83H
\81[
\83}
\83b
\83g
\83f
\83X
\83N
\83\8a\83v
\83^
\82Ì
\93Ç
\82Ý
\8d\9e\82Ý
\r
112 read_data_sync(reinterpret_cast<BYTE*>(&wfx_),min(fileHdr.FormatSize,sizeof(wfx_)));
\r
113 //offset += min(fileHdr.FormatSize,sizeof(wfx_));
\r
115 // Skip over any padding at the end of the format in the format chunk.
\r
116 if (fileHdr.FormatSize > sizeof(wfx_))
\r
118 offset_ += (fileHdr.FormatSize - sizeof(wfx_));
\r
121 // If format type is PCMWAVEFORMAT, convert to valid WAVEFORMATEX structure.
\r
122 if (wfx_.Format.wFormatTag == WAVE_FORMAT_PCM)
\r
124 wfx_.Format.cbSize = 0;
\r
127 // If format type is WAVEFORMATEX, convert to WAVEFORMATEXTENSIBLE.
\r
128 if (wfx_.Format.wFormatTag == WAVE_FORMAT_PCM ||
\r
129 wfx_.Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
\r
131 if (wfx_.Format.wFormatTag == WAVE_FORMAT_PCM)
\r
133 wfx_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
\r
137 wfx_.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
\r
139 wfx_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
\r
141 // Note that the WAVEFORMATEX structure is valid for
\r
142 // representing wave formats with only 1 or 2 channels.
\r
143 if (wfx_.Format.nChannels == 1)
\r
145 wfx_.dwChannelMask = SPEAKER_FRONT_CENTER;
\r
147 else if (wfx_.Format.nChannels == 2)
\r
149 wfx_.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
\r
153 throw file_error_exception(std::wstring(L"
\83T
\83|
\81[
\83g
\82µ
\82Ä
\82¢
\82È
\82¢.WAV
\83t
\83@
\83C
\83\8b\82Å
\82·
\81B"));
\r
155 wfx_.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
\r
156 wfx_.Samples.wValidBitsPerSample = wfx_.Format.wBitsPerSample;
\r
159 // This wave file reader understands only PCM and IEEE float formats.
\r
160 if (wfx_.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE ||
\r
161 wfx_.SubFormat != KSDATAFORMAT_SUBTYPE_PCM &&
\r
162 wfx_.SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
\r
164 throw file_error_exception(std::wstring(L"
\83T
\83|
\81[
\83g
\82µ
\82Ä
\82¢
\82È
\82¢.WAV
\83t
\83@
\83C
\83\8b\82Å
\82·
\81B"));
\r
167 //
\83f
\81[
\83^
\83`
\83\83\83\93\83N
\82ð
\8c\9f\8dõ
\82·
\82é
\81B
\82»
\82Ì
\91¼
\82Ì
\83`
\83\83\83\93\83N
\82Í
\93Ç
\82Ý
\94ò
\82Î
\82·
\81B
\r
168 ChunkHeader chunkHdr; ///
\83`
\83\83\83\93\83N
\83w
\83b
\83_
\r
171 // Read header at start of next chunk of file.
\r
172 data_chunk_position = offset_;
\r
173 read_data_sync(reinterpret_cast<BYTE*>(&chunkHdr),sizeof(ChunkHeader));
\r
174 if (chunkHdr.ChunkType == FOURCC("data"))
\r
176 break; // found start of data chunk
\r
180 // We've found the start of the data chunk. We're reader_ready to start
\r
181 // playing wave data...
\r
182 total_data_bytes_ = chunkHdr.ChunkSize;
\r
183 data_bytes_remaining_ = total_data_bytes_;
\r
184 if (total_data_bytes_ == 0)
\r
186 throw file_error_exception(std::wstring(L"
\83t
\83@
\83C
\83\8b\83T
\83C
\83Y
\82ª
\95s
\90³
\82Å
\82·
\81B"));
\r
188 stream_status_ = true;
\r
189 } catch (exception& e) {
\r
190 stream_status_ = false;
\r
198 async_reader::~async_reader()
\r
200 //
\8ec
\82Á
\82Ä
\82¢
\82éI/O
\82Í
\83L
\83\83\83\93\83Z
\83\8b\82·
\82é
\r
201 if(async_reading_){
\r
202 DWORD numbytes_copied;
\r
203 DWORD res = GetOverlappedResult(file_.get(),&overlapped_,(LPDWORD)&numbytes_copied,FALSE);
\r
206 switch(GetLastError())
\r
208 case ERROR_IO_INCOMPLETE:
\r
209 case ERROR_IO_PENDING:
\r
210 ::CancelIoEx(file_.get(),&overlapped_);
\r
211 WaitForSingleObject(event_.get(),INFINITE);
\r
217 //
\83t
\83@
\83C
\83\8b\82ð
\83N
\83\8d\81[
\83Y
\82·
\82é
\r
226 // Reset the file pointer to the start of the wave data.
\r
228 void async_reader::reset_data_position()
\r
230 if (!stream_status_ )
\r
232 throw file_error_exception(std::wstring(L"
\83t
\83@
\83C
\83\8b\82ª
\83I
\81[
\83v
\83\93\82³
\82ê
\82Ä
\82¢
\82Ü
\82¹
\82ñ
\81B"));
\r
235 // Read the header for the data chunk.
\r
236 ChunkHeader chunkHdr;
\r
237 offset_ = data_chunk_position;
\r
238 read_data_sync(reinterpret_cast<BYTE*>(&chunkHdr),sizeof(chunkHdr));
\r
240 // Sanity check: The chunk header shouldn't have changed.
\r
241 if (chunkHdr.ChunkType != FOURCC("data") ||
\r
242 chunkHdr.ChunkSize != total_data_bytes_)
\r
244 throw file_error_exception(std::wstring(L"
\95s
\90³
\82ÈWAV
\83t
\83@
\83C
\83\8b\82Å
\82·
\81B"));
\r
247 data_bytes_remaining_ = total_data_bytes_;
\r
251 void async_reader::seek(uint64_t pos)
\r
253 if (!stream_status_ )
\r
255 throw file_error_exception(std::wstring(L"
\83t
\83@
\83C
\83\8b\82ª
\83I
\81[
\83v
\83\93\82³
\82ê
\82Ä
\82¢
\82Ü
\82¹
\82ñ
\81B"));
\r
257 pos = (pos / get_wave_format().Format.nBlockAlign) * get_wave_format().Format.nBlockAlign;
\r
258 data_bytes_remaining_ = total_data_bytes_ - pos;
\r
259 offset_ = pos + data_chunk_position + sizeof(ChunkHeader);
\r
260 overlapped_.Pointer = (PVOID)pos;
\r
265 // Load next block of wave data from file into playback buffer.
\r
266 // In repeat mode, when we reach the end of the wave data in the
\r
267 // file, we just reset the file pointer back to the start of the
\r
268 // data and continue filling the caller's buffer until it is full.
\r
269 // In single-reader_read_file mode, once we reach the end of the wave data in
\r
270 // the file, we just fill the buffer with silence instead of with
\r
273 void async_reader::read_data(BYTE *buffer, uint64_t numbytes_to_copy)
\r
275 assert(async_reading_ == false);
\r
277 if (!stream_status_ )
\r
279 throw file_error_exception(std::wstring(L"
\83t
\83@
\83C
\83\8b\82ª
\83I
\81[
\83v
\83\93\82³
\82ê
\82Ä
\82¢
\82Ü
\82¹
\82ñ
\81B"));
\r
282 if (buffer == NULL)
\r
284 throw file_error_exception(L"
\83o
\83b
\83t
\83@
\83A
\83h
\83\8c\83X
\82ª
\96³
\8cø
\82Å
\82·
\81B");
\r
287 if (numbytes_to_copy == 0)
\r
289 throw file_error_exception(L"
\93Ç
\82Ý
\8d\9e\82Ý
\83o
\83C
\83g
\90\94\82Ì
\8ew
\92è
\82ª0
\82Å
\82·
\81B");
\r
292 ULONG numbytes_copied;
\r
293 overlapped_.Pointer = (PVOID)offset_;
\r
294 int result = ReadFile(file_.get(),buffer,numbytes_to_copy,&numbytes_copied,&overlapped_);
\r
297 DWORD err = GetLastError();
\r
300 case ERROR_HANDLE_EOF:
\r
302 if(numbytes_to_copy > numbytes_copied)
\r
304 BYTE silence = (wfx_.Format.wBitsPerSample==8) ? 0x80 : 0;
\r
305 memset(buffer + numbytes_copied, silence, numbytes_to_copy - numbytes_copied);
\r
307 offset_ += numbytes_copied;
\r
308 async_reading_ = false;
\r
310 if(reader_repeat_mode_){
\r
311 reset_data_position();
\r
313 throw file_eof_exception(std::wstring(L"
\83t
\83@
\83C
\83\8b\82Ì
\8fI
\82í
\82è
\82É
\92B
\82µ
\82½
\82½
\82ß
\81A
\82±
\82ê
\88È
\8fã
\83f
\81[
\83^
\93Ç
\82Ý
\8d\9e\82Þ
\82±
\82Æ
\82ª
\82Å
\82«
\82Ü
\82¹
\82ñ
\81B"));
\r
316 case ERROR_IO_PENDING:
\r
318 // DWORD res = GetOverlappedResult(file_.get(),&overlapped_,&num_of_read,TRUE);
\r
321 // throw file_error_exception(win32_error_exception::get_last_error_str());
\r
323 // if(res != numbytes_to_copy)
\r
325 // throw file_error_exception(std::wstring(L"
\93Ç
\82Ý
\8d\9e\82ñ
\82¾
\83f
\81[
\83^
\83T
\83C
\83Y
\82ª
\8d\87\82¢
\82Ü
\82¹
\82ñ
\81B"));
\r
329 async_reading_ = true;
\r
332 throw file_error_exception(win32_error_exception::get_last_error_str(err));
\r
336 data_bytes_remaining_ -= numbytes_copied;
\r
337 offset_ += numbytes_copied;
\r
338 async_reading_ = false;
\r
339 //current += numbytes_copied;
\r
343 //if(numbytes_copied > data_bytes_remaining_)
\r
345 // if (fread(current, 1, data_bytes_remaining_, file_) != data_bytes_remaining_)
\r
347 // throw exception(L"
\95s
\90³
\82ÈWAV
\83t
\83@
\83C
\83\8b\82Å
\82·
\81B");
\r
349 // current += data_bytes_remaining_;
\r
350 // numbytes_copied -= data_bytes_remaining_;
\r
351 // data_bytes_remaining_ = 0;
\r
353 // // The file pointer now sits at the end of the data chunk.
\r
354 // // Are we operating in repeat mode?
\r
355 // if (!reader_repeat_mode_)
\r
357 // // Nope, we're operating in single-reader_read_file mode. Fill
\r
358 // // the rest of the buffer with silence and return.
\r
359 // BYTE silence = (wfx_.Format.wBitsPerSample==8) ? 0x80 : 0;
\r
360 // memset(current, silence, numbytes_copied);
\r
361 // return; // yup, we're done
\r
363 // // Yes, we're operating in repeat mode, so loop back to
\r
364 // // the start of the wave data in the file's data chunk
\r
365 // // and continue loading data into the caller's buffer.
\r
366 // reset_data_position();
\r
370 //assert(numbytes_copied > 0);
\r
371 //assert(numbytes_copied <= data_bytes_remaining_);
\r
373 //// The remainder of the data chunk is big enough to
\r
374 //// completely fill the remainder of the caller's buffer.
\r
375 //if (fread(buffer, 1, numbytes_copied, file_) != numbytes_copied)
\r
377 // throw exception(L"
\95s
\90³
\82ÈWAV
\83t
\83@
\83C
\83\8b\82Å
\82·
\81B");
\r
379 //data_bytes_remaining_ -= numbytes_copied;
\r
380 //current += numbytes_copied;
\r
383 void async_reader::read_data_sync(BYTE *buffer, uint64_t numbytes_to_copy)
\r
385 uint32_t numbytes_copied(0);
\r
386 overlapped_.Pointer = (PVOID)offset_;
\r
388 int result = ReadFile(file_.get(),buffer, numbytes_to_copy, (LPDWORD)&numbytes_copied, &overlapped_);
\r
392 uint32_t err = GetLastError();
\r
395 case ERROR_HANDLE_EOF:
\r
397 offset_ += numbytes_copied;
\r
398 //if(reader_repeat_mode_){
\r
399 // reset_data_position();
\r
401 throw file_eof_exception(std::wstring(L"
\83t
\83@
\83C
\83\8b\82Ì
\8fI
\82í
\82è
\82É
\92B
\82µ
\82½
\82½
\82ß
\81A
\83w
\83b
\83_
\82ð
\93Ç
\82Ý
\8d\9e\82Þ
\82±
\82Æ
\82ª
\82Å
\82«
\82Ü
\82¹
\82ñ
\81B"));
\r
404 case ERROR_IO_PENDING:
\r
406 DWORD res = GetOverlappedResult(file_.get(),&overlapped_,(LPDWORD)&numbytes_copied,TRUE);
\r
409 throw file_error_exception(win32_error_exception::get_last_error_str());
\r
411 if(numbytes_copied != numbytes_to_copy)
\r
413 throw file_error_exception(std::wstring(L"
\93Ç
\82Ý
\8d\9e\82ñ
\82¾
\83f
\81[
\83^
\83T
\83C
\83Y
\82ª
\8d\87\82¢
\82Ü
\82¹
\82ñ
\81B"));
\r
415 offset_ += numbytes_copied;
\r
420 throw file_error_exception(win32_error_exception::get_last_error_str(err));
\r
424 offset_ += numbytes_copied;
\r
428 void async_reader::wait(int timer)
\r
430 if(!async_reading_)
\r
435 uint32_t numbytes_copied(0);
\r
436 DWORD res = GetOverlappedResult(file_.get(),&overlapped_,(LPDWORD)&numbytes_copied,TRUE);
\r
437 //
\83G
\83\89\81[
\83`
\83F
\83b
\83N
\r
440 DWORD err = GetLastError();
\r
443 case ERROR_HANDLE_EOF:
\r
445 // Handle an end of file
\r
446 //if(reader_repeat_mode_){
\r
447 // reset_data_position();
\r
449 throw file_eof_exception(win32_error_exception::get_last_error_str(err));
\r
454 throw file_error_exception(win32_error_exception::get_last_error_str(err));
\r
459 ResetEvent(event_.get());
\r
460 offset_ += numbytes_copied;
\r
461 data_bytes_remaining_ -= numbytes_copied;
\r
462 if(data_bytes_remaining_ <= 0 && reader_repeat_mode_)
\r
464 reset_data_position();
\r
466 async_reading_ = false;
\r