--- /dev/null
+/* 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;
+}
+
+/* */
+