OSDN Git Service

add QTTA Reader API.
authorNoumi Akira <noumiakira@users.sourceforge.jp>
Thu, 20 Aug 2009 06:29:39 +0000 (15:29 +0900)
committerNoumi Akira <noumiakira@users.sourceforge.jp>
Thu, 20 Aug 2009 06:29:39 +0000 (15:29 +0900)
Lib/QTTA/QTTA.def
Lib/QTTA/QTTA.vcproj
Lib/QTTA/TTAReader.c [new file with mode: 0644]
Lib/QTTA/TTAReader.h [new file with mode: 0644]

index e5b4c00..844e3e5 100644 (file)
@@ -6,3 +6,12 @@ QTTA_CreateDecoder
 QTTA_ReleaseDecoder
 QTTA_SetupDecoder
 QTTA_DecodeFrame
+
+QTTA_CreateReader
+QTTA_ReleaseReader
+QTTA_OpenReader
+QTTA_OpenReader_IStream
+QTTA_GetFormat
+QTTA_Seek
+QTTA_Decode
+
index 7b4e9d1..c259168 100644 (file)
                                        />
                                </FileConfiguration>
                        </File>
+                       <File
+                               RelativePath=".\TTAReader.c"
+                               >
+                       </File>
                </Filter>
                <Filter
                        Name="\83w\83b\83_\81\83t\83@\83C\83\8b"
                                RelativePath=".\TTADecoder.h"
                                >
                        </File>
+                       <File
+                               RelativePath=".\TTAReader.h"
+                               >
+                       </File>
                </Filter>
                <Filter
                        Name="\83\8a\83\\81[\83\83t\83@\83C\83\8b"
diff --git a/Lib/QTTA/TTAReader.c b/Lib/QTTA/TTAReader.c
new file mode 100644 (file)
index 0000000..68401ee
--- /dev/null
@@ -0,0 +1,607 @@
+/* TTAReader.c */
+/* 2009/08/18  */
+
+#include "StdAfx.h"
+
+#include "TTAReader.h"
+
+#include "TTADecoder.h"
+
+/* */
+
+typedef VOID* (*QTTA_Allocate_t  )(VOID*, SIZE_T);
+typedef VOID* (*QTTA_Reallocate_t)(VOID*, VOID*, SIZE_T);
+typedef VOID  (*QTTA_Free_t      )(VOID*, VOID*);
+
+struct QTTA_Allocator {
+
+       VOID* Context;
+
+       QTTA_Allocate_t   Allocate;
+       QTTA_Reallocate_t Reallocate;
+       QTTA_Free_t       Free;
+
+};
+
+typedef struct QTTA_Allocator QTTA_Allocator_t;
+
+/* */
+
+typedef INT32 (*QTTA_Read_t)(VOID*, VOID*, INT32);
+typedef BOOL  (*QTTA_Seek_t)(VOID*, INT64);
+
+struct QTTA_StreamReader {
+
+       VOID* Context;
+
+       QTTA_Read_t Read;
+       QTTA_Seek_t Seek;
+
+};
+
+typedef struct QTTA_StreamReader QTTA_StreamReader_t;
+
+/* */
+
+QTTA_Allocator_t* Allocator_Get();
+
+/* */
+
+void QTTA_StreamReader_Init(
+       QTTA_StreamReader_t* t,
+       FILE*                fp);
+
+void QTTA_StreamReader_IStream(
+       QTTA_StreamReader_t* t,
+       IStream*             p);
+
+/* */
+
+/* QTTA_MemoryPool */
+struct QTTA_MemoryPool {
+
+       VOID*  Block;
+       SIZE_T TotalSize;
+
+}; /* QTTA_MemoryPool */
+
+typedef struct QTTA_MemoryPool QTTA_MemoryPool_t;
+
+/* */
+
+void QTTA_MemoryPool_Init(
+       QTTA_MemoryPool_t* t);
+
+void QTTA_MemoryPool_Release(
+       QTTA_MemoryPool_t* t,
+       QTTA_Allocator_t*  alloc);
+
+VOID* QTTA_MemoryPool_Allocate(
+       QTTA_MemoryPool_t* t,
+       QTTA_Allocator_t*  alloc,
+       SIZE_T             cb);
+
+/* */
+
+static VOID* s_allocate(VOID* ctx, SIZE_T sz)
+{
+       return _aligned_malloc(sz, 0x10);
+}
+
+static VOID* s_reallocate(VOID* ctx, VOID* pv, SIZE_T sz)
+{
+       return _aligned_realloc(pv, sz, 0x10);
+}
+
+static VOID s_free(VOID* ctx, VOID* pv)
+{
+       _aligned_free(pv);
+}
+
+QTTA_Allocator_t* Allocator_Get()
+{
+       static QTTA_Allocator_t s_allocator = {
+               0,
+               s_allocate,
+               s_reallocate,
+               s_free
+       };
+
+       return &s_allocator;
+}
+
+/* */
+
+static INT32 s_read(VOID* ctx, VOID* pv, INT32 sz)
+{
+       return fread(pv, 1, sz, (FILE*)ctx);
+}
+
+static BOOL  s_seek(VOID* ctx, INT64 pos)
+{
+       if (_fseeki64((FILE*)ctx, pos, SEEK_SET) != 0) {
+               return FALSE;
+       }
+       return TRUE;
+}
+
+void QTTA_StreamReader_Init(
+       QTTA_StreamReader_t* t,
+       FILE*              fp)
+{
+       t->Context = fp;
+
+       t->Read = s_read;
+       t->Seek = s_seek;
+}
+
+/* */
+
+static INT32 s_reads(VOID* ctx, VOID* pv, INT32 sz)
+{
+       IStream* p = (IStream*)ctx;
+       ULONG cb = 0;
+       HRESULT hRslt = p->lpVtbl->Read(p, pv, sz, &cb);
+       if (FAILED(hRslt)) {
+               return 0;
+       }
+       return cb;
+}
+
+static BOOL  s_seeks(VOID* ctx, INT64 pos)
+{
+       IStream* p = (IStream*)ctx;
+       LARGE_INTEGER  li;
+       ULARGE_INTEGER np;
+       HRESULT hRslt;
+       li.QuadPart = pos;
+       hRslt = p->lpVtbl->Seek(p, li, STREAM_SEEK_SET, &np);
+       if (FAILED(hRslt)) {
+               return FALSE;
+       }
+       return TRUE;
+}
+
+void QTTA_StreamReader_IStream(
+       QTTA_StreamReader_t* t,
+       IStream*           p)
+{
+       t->Context = p;
+
+       t->Read = s_reads;
+       t->Seek = s_seeks;
+}
+
+/* */
+
+struct MemoryBlock;
+
+typedef struct MemoryBlock MemoryBlock_t;
+
+struct MemoryBlock {
+
+       MemoryBlock_t* Next;
+
+       SIZE_T Size;
+
+       UINT32 Padding[2];
+
+};
+
+/* */
+
+void QTTA_MemoryPool_Init(
+       QTTA_MemoryPool_t* t)
+{
+       t->Block     = NULL;
+       t->TotalSize = 0;
+}
+
+void QTTA_MemoryPool_Release(
+       QTTA_MemoryPool_t* t,
+       QTTA_Allocator_t*  alloc)
+{
+       MemoryBlock_t* p = (MemoryBlock_t*)(t->Block);
+       while (p != NULL) {
+               MemoryBlock_t* n = p->Next;
+               alloc->Free(alloc->Context, p);
+               p = n;
+       }
+
+       t->Block     = NULL;
+       t->TotalSize = 0;
+}
+
+VOID* QTTA_MemoryPool_Allocate(
+       QTTA_MemoryPool_t* t,
+       QTTA_Allocator_t*  alloc,
+       SIZE_T             cb)
+{
+       MemoryBlock_t* b = (MemoryBlock_t*)alloc->Allocate(
+               alloc->Context,
+               sizeof(MemoryBlock_t) + cb);
+       if (b == NULL) {
+               return NULL;
+       }
+
+       b->Next = t->Block;
+       b->Size = cb;
+
+       t->Block      = b;
+       t->TotalSize += cb;
+
+       return b + 1;
+}
+
+/* */
+
+#pragma pack(push, 2)
+
+struct Header {
+
+       UINT8  Signature[4];
+
+       UINT16 Format;
+       UINT16 Channels;
+       UINT16 BitsPerSample;
+       UINT32 SamplingRate;
+       UINT32 Samples;
+
+       UINT32 CRC32;
+
+}; /* Header */
+
+typedef struct Header Header_t;
+
+#pragma pack(pop)
+
+const DOUBLE FRAME_TIME = 1.04489795918367346939;
+
+/* */
+
+struct QTTA_Reader {
+
+       QTTA_StreamReader_t Stream;
+
+       QTTA_MemoryPool_t Pool;
+
+       QTTA_Format_t Format;
+
+       INT32 SamplesPerFrame;
+       INT32 Frames;
+
+       UINT32* FrameSize;
+       INT64*  FramePos;
+
+       QTTADecoder_t* Decoder;
+
+       FILE* fp;
+
+       IStream* p;
+
+       VOID* Buffer;
+       INT32 BufferSize;
+
+       INT64 Position;
+       INT32 FramePosition;
+
+       const INT16* SampleBuffer;
+       INT32        PendingSamples;
+
+}; /* QTTA_Reader */
+
+/* */
+
+QTTA_Reader_t* QTTA_CreateReader(void)
+{
+       QTTA_Allocator_t* allocator = Allocator_Get();
+
+       QTTA_Reader_t* t = (QTTA_Reader_t*)malloc(sizeof(QTTA_Reader_t));
+       if (t == NULL) {
+               return NULL;
+       }
+
+       memset(t, 0, sizeof(QTTA_Reader_t));
+
+       QTTA_MemoryPool_Init(&(t->Pool));
+
+       t->Decoder = NULL;
+
+       t->fp = NULL;
+       t->p  = NULL;
+
+       t->Buffer     = NULL;
+       t->BufferSize = 0;
+
+       return t;
+}
+
+void QTTA_ReleaseReader(QTTA_Reader_t* t)
+{
+       if (t != NULL) {
+               QTTA_Allocator_t* allocator = Allocator_Get();
+
+               QTTA_MemoryPool_Release(&(t->Pool), allocator);
+
+               if (t->Decoder != NULL) {
+                       QTTA_ReleaseDecoder(t->Decoder);
+               }
+
+               if (t->fp != NULL) {
+                       fclose(t->fp);
+               }
+
+               if (t->p != NULL) {
+                       t->p->lpVtbl->Release(t->p);
+               }
+
+               free(t);
+       }
+}
+
+/* */
+
+static BOOL SetupReader(
+       QTTA_Reader_t* t)
+{
+       INT64 pos = 0;
+
+       QTTA_Allocator_t* allocator = Allocator_Get();
+
+       Header_t header = { 0 };
+
+       INT32 cb = t->Stream.Read(t->Stream.Context, &header, sizeof(header));
+       if (cb != sizeof(header)) {
+               return FALSE;
+       }
+
+       pos += cb;
+
+       if (memcmp(header.Signature, "TTA1", 4) != 0) {
+               return FALSE;
+       }
+
+       if (header.Format != 1) {
+               return FALSE;
+       }
+
+       if (header.Channels != 1 &&
+               header.Channels != 2) {
+               return FALSE;
+       }
+
+       if (header.BitsPerSample != 16) {
+               return FALSE;
+       }
+
+       /* CRC32 */
+
+       {
+               DOUBLE dSamplesPerFrame = FRAME_TIME * header.SamplingRate;
+
+               t->SamplesPerFrame = (INT32)dSamplesPerFrame;
+
+               t->Format.SamplingRate = header.SamplingRate;
+               t->Format.Channels     = header.Channels;
+               t->Format.Duration     = header.Samples;
+
+               t->Frames = (INT32)((t->Format.Duration + t->SamplesPerFrame - 1) / t->SamplesPerFrame);
+       }
+
+       t->FrameSize = (UINT32*)QTTA_MemoryPool_Allocate(&(t->Pool), allocator, (t->Frames + 1) * sizeof(UINT32));
+       if (t->FrameSize == NULL) {
+               return FALSE;
+       }
+
+       cb = t->Stream.Read(t->Stream.Context, t->FrameSize, (t->Frames + 1) * sizeof(UINT32));
+       if (cb != (t->Frames + 1) * sizeof(UINT32)) {
+               return FALSE;
+       }
+
+       pos += cb;
+
+       /* CRC32 */
+
+       t->FramePos = (INT64*)QTTA_MemoryPool_Allocate(&(t->Pool), allocator, t->Frames * sizeof(INT64));
+       if (t->FramePos == NULL) {
+               return FALSE;
+       }
+
+       {
+               INT32 i;
+               for (i = 0; i < t->Frames; i++) {
+                       t->FramePos[i] = pos;
+                       pos += t->FrameSize[i];
+               }
+       }
+
+       t->Decoder = QTTA_CreateDecoder();
+       if (t->Decoder == NULL) {
+               return FALSE;
+       }
+
+       if (!QTTA_SetupDecoder(t->Decoder, t->Format.Channels, t->SamplesPerFrame)) {
+               return FALSE;
+       }
+
+       t->Position      = 0;
+       t->FramePosition = 0;
+
+       t->SampleBuffer   = NULL;
+       t->PendingSamples = 0;
+
+       return TRUE;
+}
+
+BOOL QTTA_OpenReader(
+       QTTA_Reader_t* t,
+       const WCHAR*   path)
+{
+       FILE* fp = NULL;
+
+       _wfopen_s(&fp, path, L"rb");
+       if (fp == NULL) {
+               return FALSE;
+       }
+
+       QTTA_StreamReader_Init(&(t->Stream), fp);
+
+       if (!SetupReader(t)) {
+               fclose(fp);
+               return FALSE;
+       }
+
+       t->fp = fp;
+
+       return TRUE;
+}
+
+BOOL QTTA_OpenReader_IStream(
+       QTTA_Reader_t* t,
+       IStream*       p)
+{
+       QTTA_StreamReader_IStream(&(t->Stream), p);
+
+       if (!SetupReader(t)) {
+               return FALSE;
+       }
+
+       t->p = p;
+       t->p->lpVtbl->AddRef(t->p);
+
+       return TRUE;
+}
+
+const QTTA_Format_t* QTTA_GetFormat(
+       QTTA_Reader_t* t)
+{
+       return &(t->Format);
+}
+
+/* */
+
+BOOL QTTA_Seek(
+       QTTA_Reader_t* t,
+       INT64          sample)
+{
+       INT32 fp = (INT32)(sample / t->SamplesPerFrame);
+
+       if (fp < 0 || fp >= t->Frames) {
+               return FALSE;
+       }
+
+       if (!t->Stream.Seek(t->Stream.Context, t->FramePos[fp])) {
+               return FALSE;
+       }
+
+       t->Position      = sample;
+       t->FramePosition = fp;
+
+       t->SampleBuffer   = NULL;
+       t->PendingSamples = 0;
+
+       return TRUE;
+}
+
+BOOL QTTA_Decode(
+       QTTA_Reader_t* t,
+       VOID*          buffer,
+       INT32          samples,
+       INT32*         output)
+{
+       INT32 count = 0;
+
+       *output = 0;
+
+       for (; ; ) {
+               if (t->PendingSamples > 0) {
+                       count = samples;
+                       if (count > t->PendingSamples) {
+                               count = t->PendingSamples;
+                       }
+
+                       memcpy(
+                               buffer,
+                               t->SampleBuffer,
+                               count * t->Format.Channels * sizeof(INT16));
+
+                       t->SampleBuffer   += count * t->Format.Channels;
+                       t->PendingSamples -= count;
+
+                       t->Position += count;
+                       break;
+               }
+
+               if (t->Position >= t->Format.Duration) {
+                       break;
+               }
+
+               {
+                       /* Decode Next Frame */
+                       QTTA_Output_t dout = { 0 };
+
+                       INT32 cb = t->FrameSize[t->FramePosition], rb;
+
+                       if (cb > t->BufferSize) {
+                               QTTA_Allocator_t* allocator = Allocator_Get();
+
+                               INT32 ns = 0x10000;
+                               while (ns < cb) {
+                                       ns <<= 1;
+                               }
+
+                               t->Buffer = QTTA_MemoryPool_Allocate(&(t->Pool), allocator, ns);
+                               if (t->Buffer == NULL) {
+                                       return FALSE;
+                               }
+
+                               t->BufferSize = ns;
+                       }
+
+                       rb = t->Stream.Read(t->Stream.Context, t->Buffer, cb);
+                       if (rb != cb) {
+                               return FALSE;
+                       }
+
+                       /* CRC32 */
+
+                       if (cb < 4) {
+                               return FALSE;
+                       }
+
+                       if (!QTTA_DecodeFrame(
+                               t->Decoder,
+                               t->Buffer,
+                               cb - 4,
+                               &dout)) {
+                               return FALSE;
+                       }
+
+                       t->SampleBuffer   = dout.Sample;
+                       t->PendingSamples = dout.Length;
+
+                       {
+                               INT64 np = (INT64)(t->FramePosition) * t->SamplesPerFrame;
+                               INT32 ds = (INT32)(t->Position - np);
+
+                               t->SampleBuffer   += ds * t->Format.Channels;
+                               t->PendingSamples -= ds;
+
+                               if (np + dout.Length > t->Format.Duration) {
+                                       INT32 es = (INT32)(np + dout.Length - t->Format.Duration);
+
+                                       t->PendingSamples -= es;
+                               }
+                       }
+
+                       t->FramePosition += 1;
+               }
+       }
+
+       *output = count;
+
+       return TRUE;
+}
+
+/* */
+
diff --git a/Lib/QTTA/TTAReader.h b/Lib/QTTA/TTAReader.h
new file mode 100644 (file)
index 0000000..1d3df90
--- /dev/null
@@ -0,0 +1,59 @@
+/* TTAReader.h */
+/* 2009/08/18  */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/* */
+
+struct QTTA_Format {
+
+       INT32 SamplingRate;
+       INT32 Channels;
+       INT64 Duration;
+
+}; /* QTTA_Format */
+
+typedef struct QTTA_Format QTTA_Format_t;
+
+/* */
+
+struct QTTA_Reader;
+
+typedef struct QTTA_Reader QTTA_Reader_t;
+
+QTTA_Reader_t* QTTA_CreateReader(void);
+
+void QTTA_ReleaseReader(QTTA_Reader_t* t);
+
+BOOL QTTA_OpenReader(
+       QTTA_Reader_t* t,
+       const WCHAR*   path);
+
+BOOL QTTA_OpenReader_IStream(
+       QTTA_Reader_t* t,
+       IStream*       p);
+
+const QTTA_Format_t* QTTA_GetFormat(
+       QTTA_Reader_t* t);
+
+BOOL QTTA_Seek(
+       QTTA_Reader_t* t,
+       INT64          sample);
+
+BOOL QTTA_Decode(
+       QTTA_Reader_t* t,
+       VOID*          buffer,
+       INT32          samples,
+       INT32*         output);
+
+/* */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+