public void Set(int size, int channels) { RuintList *list; uint offset = _entries.Address; int dataOffset = 0x60 + (channels * 8); _tag = Tag; _size = size; //Set entry offsets _entries.Entries[0] = 0x18; _entries.Entries[1] = 0x4C; _entries.Entries[2] = 0x5C; //Audio info //HEADPart1* part1 = Part1; //Set single channel info list = Part2; list->_numEntries._data = 1; //Number is little-endian list->Entries[0] = 0x58; *(AudioFormatInfo *)list->Get(offset, 0) = new AudioFormatInfo(2, 0, 1, 0); //Set adpcm infos list = Part3; list->_numEntries._data = channels; //little-endian for (int i = 0; i < channels; i++) { //Set initial pointer list->Entries[i] = dataOffset; //Set embedded pointer *(ruint *)(offset + dataOffset) = dataOffset + 8; dataOffset += 8; //Set info //*(ADPCMInfo*)(offset + dataOffset) = info[i]; dataOffset += ADPCMInfo.Size; //Set padding //*(short*)(offset + dataOffset) = 0; //dataOffset += 2; } //Fill remaining int *p = (int *)(offset + dataOffset); for (dataOffset += 8; dataOffset < size; dataOffset += 4) { *p++ = 0; } }
public unsafe StrmDataInfo(FSTMDataInfo o, int dataOffset) { _format = o._format; _sampleRate = checked ((ushort)(int)o._sampleRate); _blockHeaderOffset = 0; _loopStartSample = o._loopStartSample; _numSamples = o._numSamples; _dataOffset = dataOffset; _numBlocks = o._numBlocks; _blockSize = o._blockSize; _samplesPerBlock = o._samplesPerBlock; _lastBlockSize = o._lastBlockSize; _lastBlockSamples = o._lastBlockSamples; _lastBlockTotal = o._lastBlockTotal; _dataInterval = o._dataInterval; _bitsPerSample = o._bitsPerSample; }
public CSTMDataInfo(StrmDataInfo o, int dataOffset = 0x18) { _format = o._format; _sampleRate = o._sampleRate; _loopStartSample = o._loopStartSample; _numSamples = o._numSamples; _numBlocks = o._numBlocks; _blockSize = o._blockSize; _samplesPerBlock = o._samplesPerBlock; _lastBlockSize = o._lastBlockSize; _lastBlockSamples = o._lastBlockSamples; _lastBlockTotal = o._lastBlockTotal; _bitsPerSample = o._bitsPerSample; _dataInterval = o._dataInterval; _sampleDataRef._type = CSTMReference.RefType.SampleData; _sampleDataRef._padding = 0; _sampleDataRef._dataOffset = dataOffset; }
public static unsafe FileMap Encode(IAudioStream stream, IProgressTracker progress) { int tmp; bool looped = stream.IsLooping; int channels = stream.Channels; int samples; int blocks; int sampleRate = stream.Frequency; int lbSamples, lbSize, lbTotal; int loopPadding, loopStart, totalSamples; short* tPtr; if (looped) { loopStart = stream.LoopStartSample; samples = stream.LoopEndSample; //Set sample size to end sample. That way the audio gets cut off when encoding. //If loop point doesn't land on a block, pad the stream so that it does. if ((tmp = loopStart % 0x3800) != 0) { loopPadding = 0x3800 - tmp; loopStart += loopPadding; } else loopPadding = 0; totalSamples = loopPadding + samples; } else { loopPadding = loopStart = 0; totalSamples = samples = stream.Samples; } if (progress != null) progress.Begin(0, totalSamples * channels * 3, 0); blocks = (totalSamples + 0x37FF) / 0x3800; //Initialize stream info if ((tmp = totalSamples % 0x3800) != 0) { lbSamples = tmp; lbSize = (lbSamples + 13) / 14 * 8; lbTotal = lbSize.Align(0x20); } else { lbSamples = 0x3800; lbTotal = lbSize = 0x2000; } //Get section sizes int rstmSize = 0x40; int headSize = (0x68 + (channels * 0x40)).Align(0x20); int adpcSize = ((blocks - 1) * 4 * channels + 0x10).Align(0x20); int dataSize = ((blocks - 1) * 0x2000 + lbTotal) * channels + 0x20; //Create file map FileMap map = FileMap.FromTempFile(rstmSize + headSize + adpcSize + dataSize); //Get section pointers RSTMHeader* rstm = (RSTMHeader*)map.Address; HEADHeader* head = (HEADHeader*)((int)rstm + rstmSize); ADPCHeader* adpc = (ADPCHeader*)((int)head + headSize); RSTMDATAHeader* data = (RSTMDATAHeader*)((int)adpc + adpcSize); //Initialize sections rstm->Set(headSize, adpcSize, dataSize); head->Set(headSize, channels); adpc->Set(adpcSize); data->Set(dataSize); //Set HEAD data StrmDataInfo* part1 = head->Part1; part1->_format = new AudioFormatInfo(2, (byte)(looped ? 1 : 0), (byte)channels, 0); part1->_sampleRate = (ushort)sampleRate; part1->_blockHeaderOffset = 0; part1->_loopStartSample = loopStart; part1->_numSamples = totalSamples; part1->_dataOffset = rstmSize + headSize + adpcSize + 0x20; part1->_numBlocks = blocks; part1->_blockSize = 0x2000; part1->_samplesPerBlock = 0x3800; part1->_lastBlockSize = lbSize; part1->_lastBlockSamples = lbSamples; part1->_lastBlockTotal = lbTotal; part1->_dataInterval = 0x3800; part1->_bitsPerSample = 4; //Create one ADPCMInfo for each channel int* adpcData = stackalloc int[channels]; ADPCMInfo** pAdpcm = (ADPCMInfo**)adpcData; for (int i = 0; i < channels; i++) *(pAdpcm[i] = head->GetChannelInfo(i)) = new ADPCMInfo() { _pad = 0 }; //Create buffer for each channel int* bufferData = stackalloc int[channels]; short** channelBuffers = (short**)bufferData; int bufferSamples = totalSamples + 2; //Add two samples for initial yn values for (int i = 0; i < channels; i++) { channelBuffers[i] = tPtr = (short*)Marshal.AllocHGlobal(bufferSamples * 2); //Two bytes per sample //Zero padding samples and initial yn values for (int x = 0; x < (loopPadding + 2); x++) *tPtr++ = 0; } //Fill buffers stream.SamplePosition = 0; short* sampleBuffer = stackalloc short[channels]; for (int i = 2; i < bufferSamples; i++) { if (stream.SamplePosition == stream.LoopEndSample && looped) stream.SamplePosition = stream.LoopStartSample; stream.ReadSamples(sampleBuffer, 1); for (int x = 0; x < channels; x++) channelBuffers[x][i] = sampleBuffer[x]; } //Calculate coefs for (int i = 0; i < channels; i++) AudioConverter.CalcCoefs(channelBuffers[i] + 2, totalSamples, (short*)pAdpcm[i], progress); //Encode blocks byte* dPtr = (byte*)data->Data; bshort* pyn = (bshort*)adpc->Data; for (int sIndex = 0, bIndex = 1; sIndex < totalSamples; sIndex += 0x3800, bIndex++) { int blockSamples = Math.Min(totalSamples - sIndex, 0x3800); for (int x = 0; x < channels; x++) { short* sPtr = channelBuffers[x] + sIndex; //Set block yn values if (bIndex != blocks) { *pyn++ = sPtr[0x3801]; *pyn++ = sPtr[0x3800]; } //Encode block (include yn in sPtr) AudioConverter.EncodeBlock(sPtr, blockSamples, dPtr, (short*)pAdpcm[x]); //Set initial ps if (bIndex == 1) pAdpcm[x]->_ps = *dPtr; //Advance output pointer if (bIndex == blocks) { //Fill remaining dPtr += lbSize; for (int i = lbSize; i < lbTotal; i++) *dPtr++ = 0; } else dPtr += 0x2000; } if (progress != null) { if ((sIndex % 0x3800) == 0) progress.Update(progress.CurrentValue + (0x7000 * channels)); } } //Reverse coefs for (int i = 0; i < channels; i++) { short* p = pAdpcm[i]->_coefs; for (int x = 0; x < 16; x++, p++) *p = p->Reverse(); } //Write loop states if (looped) { //Can't we just use block states? int loopBlock = loopStart / 0x3800; int loopChunk = (loopStart - (loopBlock * 0x3800)) / 14; dPtr = (byte*)data->Data + (loopBlock * 0x2000 * channels) + (loopChunk * 8); tmp = (loopBlock == blocks - 1) ? lbTotal : 0x2000; for (int i = 0; i < channels; i++, dPtr += tmp) { //Use adjusted samples for yn values tPtr = channelBuffers[i] + loopStart; pAdpcm[i]->_lps = *dPtr; pAdpcm[i]->_lyn2 = *tPtr++; pAdpcm[i]->_lyn1 = *tPtr; } } //Free memory for (int i = 0; i < channels; i++) Marshal.FreeHGlobal((IntPtr)channelBuffers[i]); if (progress != null) progress.Finish(); return map; }
public static unsafe FileMap Encode(IAudioStream stream, IProgressTracker progress) { int tmp; bool looped = stream.IsLooping; int channels = stream.Channels; int samples; int blocks; int sampleRate = stream.Frequency; int lbSamples, lbSize, lbTotal; int loopPadding, loopStart, totalSamples; short* tPtr; int blockLen, samplesPerBlock; if (looped) { loopStart = stream.LoopStartSample; samples = stream.LoopEndSample; //Set sample size to end sample. That way the audio gets cut off when encoding. blockLen = (samples.Align(14) / 14 * 8); samplesPerBlock = blockLen / 8 * 14; //If loop point doesn't land on a block, pad the stream so that it does. //if ((tmp = loopStart % samplesPerBlock) != 0) //{ // loopPadding = samplesPerBlock - tmp; // loopStart += loopPadding; //} //else // loopPadding = 0; totalSamples = /*loopPadding + */samples; } else { loopPadding = 0; loopStart = 2; totalSamples = samples = stream.Samples; blockLen = (samples.Align(14) / 14 * 8); samplesPerBlock = blockLen / 8 * 14; } if (progress != null) progress.Begin(0, totalSamples * channels * 3, 0); blocks = (totalSamples + (samplesPerBlock - 1)) / samplesPerBlock; //Initialize stream info if ((tmp = totalSamples % samplesPerBlock) != 0) { lbSamples = tmp; lbSize = (lbSamples + 13) / 14 * 8; lbTotal = lbSize.Align(0x20); } else { lbSamples = samplesPerBlock; lbTotal = lbSize = blockLen; } //Get section sizes int waveSize = 0x1C, tableSize = channels * 4, channelSize = channels * 0x1C, adpcmInfoSize = channels * 0x30, entrySize = waveSize + tableSize + channelSize + adpcmInfoSize, dataSize = (((blocks - 1) * blockLen + lbTotal) * channels); //Create file map FileMap map = FileMap.FromTempFile(waveSize + channelSize + tableSize + adpcmInfoSize + dataSize); //Get section pointers WaveInfo* wave = (WaveInfo*)map.Address; wave->_format = new AudioFormatInfo(2, (byte)(looped ? 1 : 0), (byte)channels, 0); wave->_sampleRate = (ushort)sampleRate; wave->_channelInfoTableOffset = 0x1C; wave->_dataLocation = (uint)entrySize; wave->LoopSample = loopStart; wave->NumSamples = totalSamples; //Create one ChannelInfo for each channel buint* table = (buint*)((VoidPtr)wave + waveSize); ChannelInfo* channelInfo = (ChannelInfo*)((VoidPtr)wave + waveSize + tableSize); for (int i = 0; i < channels; i++) { table[i] = (uint)&channelInfo[i] - (uint)wave; channelInfo[i] = new ChannelInfo() { _volBackLeft = 1, _volBackRight = 1, _volFrontLeft = 1, _volFrontRight = 1, _adpcmInfoOffset = waveSize + tableSize + channelSize + i * 0x30 }; } //Create one ADPCMInfo for each channel int* adpcData = stackalloc int[channels]; ADPCMInfo** pAdpcm = (ADPCMInfo**)adpcData; for (int i = 0; i < channels; i++) *(pAdpcm[i] = wave->GetADPCMInfo(i)) = new ADPCMInfo(); //Create buffer for each channel int* bufferData = stackalloc int[channels]; short** channelBuffers = (short**)bufferData; int bufferSamples = totalSamples + 2; //Add two samples for initial yn values for (int i = 0; i < channels; i++) { channelBuffers[i] = tPtr = (short*)Marshal.AllocHGlobal(bufferSamples * 2); //Two bytes per sample //Zero padding samples and initial yn values //for (int x = 0; x < (loopPadding + 2); x++) // *tPtr++ = 0; } //Fill buffers stream.SamplePosition = 0; short* sampleBuffer = stackalloc short[channels]; for (int i = 2; i < bufferSamples; i++) { //if (stream.SamplePosition == stream.LoopEndSample && looped) // stream.SamplePosition = stream.LoopStartSample; stream.ReadSamples(sampleBuffer, 1); for (int x = 0; x < channels; x++) channelBuffers[x][i] = sampleBuffer[x]; } //Calculate coefs for (int i = 0; i < channels; i++) AudioConverter.CalcCoefs(channelBuffers[i] + 2, totalSamples, (short*)pAdpcm[i], progress); //Encode blocks byte* dPtr = (byte*)wave + entrySize; for (int sIndex = 0, bIndex = 1; sIndex < totalSamples; sIndex += samplesPerBlock, bIndex++) { int blockSamples = Math.Min(totalSamples - sIndex, samplesPerBlock); for (int x = 0; x < channels; x++) { channelInfo[x]._channelDataOffset = (int)(dPtr - ((byte*)wave + entrySize)); short* sPtr = channelBuffers[x] + sIndex; //Set block yn values if (bIndex != blocks) { pAdpcm[x]->_yn1 = sPtr[samplesPerBlock + 1]; pAdpcm[x]->_yn2 = sPtr[samplesPerBlock]; } //Encode block (include yn in sPtr) AudioConverter.EncodeBlock(sPtr, blockSamples, dPtr, (short*)pAdpcm[x]); //Set initial ps if (bIndex == 1) pAdpcm[x]->_ps = *dPtr; //Advance output pointer if (bIndex == blocks) { //Fill remaining dPtr += lbSize; for (int i = lbSize; i < lbTotal; i++) *dPtr++ = 0; } else dPtr += blockLen; } if (progress != null && (sIndex % samplesPerBlock) == 0) progress.Update(progress.CurrentValue + (samplesPerBlock * 2 * channels)); } //Reverse coefs for (int i = 0; i < channels; i++) { short* p = pAdpcm[i]->_coefs; for (int x = 0; x < 16; x++, p++) *p = p->Reverse(); } //Write loop states if (looped) { //Can't we just use block states? int loopBlock = loopStart / samplesPerBlock; int loopChunk = (loopStart - (loopBlock * samplesPerBlock)) / 14; dPtr = (byte*)wave + entrySize + (loopBlock * blockLen * channels) + (loopChunk * 8); tmp = (loopBlock == blocks - 1) ? lbTotal : blockLen; for (int i = 0; i < channels; i++, dPtr += tmp) { //Use adjusted samples for yn values tPtr = channelBuffers[i] + loopStart; pAdpcm[i]->_lps = *dPtr; pAdpcm[i]->_lyn2 = *tPtr++; pAdpcm[i]->_lyn1 = *tPtr; } } //Free memory for (int i = 0; i < channels; i++) Marshal.FreeHGlobal((IntPtr)channelBuffers[i]); if (progress != null) progress.Finish(); return map; }
public void Set(int size, int channels) { RuintList* list; uint offset = _entries.Address; int dataOffset = 0x60 + (channels * 8); _tag = Tag; _size = size; //Set entry offsets _entries.Entries[0] = 0x18; _entries.Entries[1] = 0x4C; _entries.Entries[2] = 0x5C; //Audio info //HEADPart1* part1 = Part1; //Set single channel info list = Part2; list->_numEntries._data = 1; //Number is little-endian list->Entries[0] = 0x58; *(AudioFormatInfo*)list->Get(offset, 0) = new AudioFormatInfo(2, 0, 1, 0); //Set adpcm infos list = Part3; list->_numEntries._data = channels; //little-endian for (int i = 0; i < channels; i++) { //Set initial pointer list->Entries[i] = dataOffset; //Set embedded pointer *(ruint*)(offset + dataOffset) = dataOffset + 8; dataOffset += 8; //Set info //*(ADPCMInfo*)(offset + dataOffset) = info[i]; dataOffset += ADPCMInfo.Size; //Set padding //*(short*)(offset + dataOffset) = 0; //dataOffset += 2; } //Fill remaining int* p = (int*)(offset + dataOffset); for (dataOffset += 8; dataOffset < size; dataOffset += 4) *p++ = 0; }