public override void OnRebuild(VoidPtr address, int length, bool force) { RBNK_WAVEHeader *header = (RBNK_WAVEHeader *)address; header->_tag = WAVEHeader.Tag; header->_list._numEntries = Children.Count; header->_length = (uint)length; ruint * table = header->_list.Entries; VoidPtr addr = table + Children.Count; VoidPtr baseAddr = _audioAddr; foreach (WAVESoundNode r in Children) { table[r.Index] = (uint)(addr - header->_list.Address); r.MoveRaw(addr, r.WorkingUncompressed.Length); WaveInfo *wave = (WaveInfo *)addr; wave->_dataLocation = (uint)(_audioAddr - baseAddr); Memory.Move(_audioAddr, r._streamBuffer.Address, (uint)r._streamBuffer.Length); _audioAddr += (uint)r._streamBuffer.Length; addr += r.WorkingUncompressed.Length; } }
public ADPCMStream(WaveInfo* pWAVE, VoidPtr dataAddr) { _dataAddress = dataAddr; ADPCMInfo*[] info; int loopBlock, loopChunk; byte* sPtr; info = new ADPCMInfo*[_numChannels = pWAVE->_format._channels]; _currentStates = new ADPCMState[_numChannels]; _loopStates = new ADPCMState[_numChannels]; _isLooped = pWAVE->_format._looped != 0; _sampleRate = pWAVE->_sampleRate; _numSamples = pWAVE->NumSamples; if (_numSamples <= 0) return; _blockLen = (_numSamples.Align(14) / 14 * 8).Align(0x20); _loopStartSample = (int)pWAVE->LoopSample; _loopEndSample = _numSamples; Init(); _blockStates = new ADPCMState[_numChannels, _numBlocks]; loopBlock = _loopStartSample / _samplesPerBlock; loopChunk = (_loopStartSample - (loopBlock * _samplesPerBlock)) / 14; int x = (loopBlock * _blockLen * _numChannels) + (loopChunk * 8); int y = (_loopStartSample / 14 * 8); sPtr = (byte*)dataAddr + x; //Get channel info for (int i = 0; i < _numChannels; i++) //{ // //sPtr = (byte*)dataAddr + pWAVE->GetChannelInfo(i)->_channelDataOffset + loopStart; info[i] = pWAVE->GetADPCMInfo(i); // //Fill loop state // _loopStates[i] = new ADPCMState(sPtr, info[i]->_lps, info[i]->_lyn1, info[i]->_lyn2, info[i]->Coefs); // //Advance source pointer for next channel // sPtr += _blockLen; //} //Fill block states in a linear fashion sPtr = (byte*)dataAddr; for (int sIndex = 0, bIndex = 0; sIndex < _numSamples; sIndex += _samplesPerBlock, bIndex++) for (int cIndex = 0; cIndex < _numChannels; cIndex++) { //sPtr = (byte*)dataAddr + pWAVE->GetChannelInfo(cIndex)->_channelDataOffset; //Get block state ADPCMInfo* i = info[cIndex]; _blockStates[cIndex, bIndex] = new ADPCMState(sPtr, i->_ps, i->_yn1, i->_yn2, i->_lps, i->_lyn1, i->_lyn2, i->Coefs); //Use ps from data stream //Advance address sPtr += (bIndex == _numBlocks - 1) ? _lastBlockSize : _blockLen; } }
public void Init(VoidPtr strmAddr, int strmLen, WaveInfo *info) { Info = *info; _streamBuffer = new UnsafeBuffer(strmLen); Memory.Move(_streamBuffer.Address, strmAddr, (uint)strmLen); _audioSource = new DataSource(_streamBuffer.Address, _streamBuffer.Length); if (info->_format._encoding == 2) { _stream = new ADPCMStream(info, _audioSource.Address); } else { _stream = new PCMStream(info, _audioSource.Address); } }
internal PCMStream(WaveInfo *pWAVE, VoidPtr dataAddr) { _frequency = pWAVE->_sampleRate; _numSamples = pWAVE->NumSamples; _numChannels = pWAVE->_format._channels; _bps = pWAVE->_format._encoding == 0 ? 8 : 16; if (_numSamples <= 0) { return; } _loopStart = (int)pWAVE->LoopSample; _loopEnd = _numSamples; _source = (short *)dataAddr; _samplePos = 0; }
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 = 0; 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 headerSize = RWAV.Size, infoSize = 8, waveSize = 0x1C, tableSize = channels * 4, channelSize = channels * 0x1C, adpcmInfoSize = channels * 0x30, entrySize = (infoSize + waveSize + tableSize + channelSize + adpcmInfoSize).Align(0x20) - 8, dataSize = (((blocks - 1) * blockLen + lbTotal) * channels) + 8; //Create file map FileMap map = FileMap.FromTempFile(headerSize + entrySize + 8 + dataSize); //Get section pointers RWAV *header = (RWAV *)map.Address; header->_header._tag = RWAV.Tag; header->_header.Endian = Endian.Big; header->_header._version = 0x102; header->_header._length = map.Length; header->_header._firstOffset = 0x20; header->_header._numEntries = 2; header->_infoOffset = 0x20; header->_infoLength = entrySize + 8; header->_dataOffset = 0x20 + entrySize + 8; header->_dataLength = dataSize; RWAVInfo *infoBlock = header->Info; infoBlock->_header._tag = RWAVInfo.Tag; infoBlock->_header._length = entrySize + 8; WaveInfo *wave = &infoBlock->_info; wave->_format = new AudioFormatInfo(2, (byte)(looped ? 1 : 0), (byte)channels, 0); wave->_sampleRate = (ushort)sampleRate; wave->_channelInfoTableOffset = 0x1C; wave->_dataLocation = (uint)(header->Data->Data - map.Address); wave->LoopSample = loopStart; wave->NumSamples = totalSamples; RWAVData *dataBlock = header->Data; dataBlock->_header._tag = RWAVData.Tag; dataBlock->_header._length = dataSize; //Create one ChannelInfo for each channel buint * table = (buint *)((VoidPtr)wave + 0x1C); 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 *)dataBlock->Data; 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 *)dataBlock->Data); 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 *)dataBlock->Data + (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); }