OggStream
昨日のOggサンプルをStreamクラスで実装してみた。
#include <windows.h> #include <stdio.h> #include <math.h> #include <vorbis/codec.h> #include <vorbis/vorbisfile.h> #using <System.dll> using namespace System; using namespace System::IO; using namespace System::Media; #pragma pack (push, 1) typedef struct { short wFormatTag; unsigned short wChannels; unsigned long dwSamplesPerSec; unsigned long dwAvgBytesVerSec; unsigned short wBlockAlign; unsigned short wBitsPerSample; } FormatChunk; typedef struct { char cRIFF[4]; int iSizeRIFF; char cType[4]; char cFmt[4]; long chunkSize; FormatChunk chunk; char cData[4]; int iSizeData; } WAVEFILEHEADER; #pragma pack (pop) ref class OggStream : Stream { WAVEFILEHEADER* header; OggVorbis_File* vf; vorbis_info* vi; int word; double sec; long long position; bool loaded; void release () { if (vf) { ov_clear (vf); delete vf; vf = NULL; } if (vi) vi = NULL; if (header) { delete header; header = NULL; } sec = 0.0; position = 0; loaded = false; } public: OggStream (const char* path) : word(2), sec(0.0), position(0), loaded (false) { FILE* fp; errno_t err; err = fopen_s (&fp, path, "rb"); if (err != 0) throw gcnew ApplicationException; vf = new OggVorbis_File; if (ov_open (fp, vf, NULL, 0) < 0) { fclose (fp); delete vf; vf = NULL; throw gcnew ApplicationException; } vi = ov_info (vf, -1); if (vi == NULL) { release (); throw gcnew ApplicationException; } header = new WAVEFILEHEADER; sec = ov_time_total (vf, -1); header->iSizeData = (LONG)ceil(vi->channels * vi->rate * sec * word); memcpy (header->cRIFF, "RIFF", 4); header->iSizeRIFF = sizeof (WAVEFILEHEADER) + header->iSizeData - 8; memcpy (header->cType, "WAVE", 4); memcpy (header->cFmt, "fmt ", 4); header->chunkSize = sizeof (FormatChunk); header->chunk.wFormatTag = WAVE_FORMAT_PCM; header->chunk.wChannels = vi->channels; header->chunk.dwSamplesPerSec = vi->rate; header->chunk.dwAvgBytesVerSec= vi->rate * vi->channels * word; header->chunk.wBlockAlign = vi->channels * word; header->chunk.wBitsPerSample = word * 8; memcpy (header->cData, "data", 4); } ~OggStream () { release (); } !OggStream () { release (); } virtual property bool CanRead { bool get () override { return true; } } virtual property bool CanWrite { bool get () override { return false; } } virtual property bool CanSeek { bool get () override { return false; } } virtual property long long Length { long long get () override { return header == NULL ? 0 : header->iSizeData; } } virtual property long long Position { long long get () override { return position; } void set (long long value) override { throw gcnew NotSupportedException; } } virtual void Flush () override {} virtual int Read (array<byte>^ buffer, int offset, int count) override { pin_ptr<unsigned char> p = &buffer [0]; char* output = reinterpret_cast<char*>(p); if (!loaded) { int n = sizeof (WAVEFILEHEADER); memcpy (output + offset, (char*)header + position, n); count -= n; offset += n; loaded = true; } int pos = position; int nWrite = ov_read (vf, output + offset, count, 0, word, 1, &pos); if (nWrite == 0) { ov_clear (vf); vf = NULL; } position = pos; return nWrite; } virtual void Write (array<byte>^ buffer, int offset, int count) override { throw gcnew NotSupportedException; } virtual long long Seek (long long offset, SeekOrigin origin) override { throw gcnew NotSupportedException; } virtual void SetLength (long long length) override { throw gcnew NotSupportedException; } }; void main (int argc, char* argv[]) { if (argc < 1) { printf ("usage: playogg.exe file(.ogg)\n"); return; } OggStream stream (argv[1]); SoundPlayer^ player = gcnew SoundPlayer (%stream); player->PlayLooping (); // Hit any key Console::Read (); }