public ADPCMStream(RSTMHeader* pRSTM, VoidPtr dataAddr)
        {
            HEADHeader* pHeader = pRSTM->HEADData;
            StrmDataInfo* part1 = pHeader->Part1;
            bshort* ynCache = (bshort*)pRSTM->ADPCData->Data;
            byte* sPtr;
            short[][] coefs;
            ADPCMInfo* info;
            int loopBlock, loopChunk;
            short yn1 = 0, yn2 = 0;

            _numChannels = part1->_format._channels;
            _isLooped = part1->_format._looped != 0;
            _sampleRate = part1->_sampleRate;
            _numSamples = part1->_numSamples;
            _numBlocks = part1->_numBlocks;
            _blockLen = part1->_blockSize;
            _loopStartSample = part1->_loopStartSample;
            _lastBlockSamples = part1->_lastBlockSamples;
            _lastBlockSize = part1->_lastBlockTotal;
            _samplesPerBlock = part1->_samplesPerBlock;
            _loopEndSample = _numSamples;

            _blockStates = new ADPCMState[_numChannels, _numBlocks];
            _currentStates = new ADPCMState[_numChannels];
            _loopStates = new ADPCMState[_numChannels];
            coefs = new short[_numChannels][];

            loopBlock = _loopStartSample / _samplesPerBlock;
            loopChunk = (_loopStartSample - (loopBlock * _samplesPerBlock)) / 14;
            sPtr = (byte*)dataAddr + (loopBlock * _blockLen * _numChannels) + (loopChunk * 8);

            //Get channel info
            for (int i = 0; i < _numChannels; i++)
            {
                info = pHeader->GetChannelInfo(i);
                //Get channel coefs
                coefs[i] = info->Coefs;
                //Fill loop state
                _loopStates[i] = new ADPCMState(sPtr, info->_lps, info->_lyn1, info->_lyn2, coefs[i]);
                //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++)
                {
                    if (bIndex > 0) //yn values will be zero if first block
                    {
                        yn1 = *ynCache++;
                        yn2 = *ynCache++;
                    }
                    //Get block state
                    _blockStates[cIndex, bIndex] = new ADPCMState(sPtr, *sPtr, yn1, yn2, coefs[cIndex]); //Use ps from data stream
                    //Advance address
                    sPtr += (bIndex == _numBlocks - 1) ? _lastBlockSize : _blockLen;
                }
        }
Пример #2
0
        public override bool OnInitialize()
        {
            if ((_name == null) && (_origPath != null))
            {
                _name = Path.GetFileNameWithoutExtension(_origPath);
            }

            base.OnInitialize();

            StrmDataInfo *part1 = Header->HEADData->Part1;

            _encoding   = part1->_format._encoding;
            _channels   = part1->_format._channels;
            _looped     = part1->_format._looped != 0;
            _sampleRate = part1->_sampleRate;
            _loopStart  = part1->_loopStartSample;
            _numSamples = part1->_numSamples;
            _dataOffset = part1->_dataOffset;
            _numBlocks  = part1->_numBlocks;
            _blockSize  = part1->_blockSize;
            _bps        = part1->_bitsPerSample;

            int offset = ((int)(Header->DATAData->Data) - (int)(Header));

            if (offset < WorkingUncompressed.Length)
            {
                _audioSource = new DataSource(Header->DATAData->Data, WorkingUncompressed.Length - offset);
                SetSizeInternal(offset);
            }

            return(false);
        }
Пример #3
0
        public override bool OnInitialize()
        {
            if (_name == null && _origPath != null)
            {
                _name = Path.GetFileNameWithoutExtension(_origPath);
            }

            base.OnInitialize();

            if (Header->_header._tag == CSTMHeader.Tag)
            {
                ShowADPCMConversionWarning();
                byte[] brstm_temp = CSTMConverter.ToRSTM((CSTMHeader *)Header);
                fixed(byte *ptr = brstm_temp)
                {
                    ReplaceRaw(ptr, brstm_temp.Length);
                    return(false);
                }
            }

            if (Header->_header._tag == FSTMHeader.Tag)
            {
                ShowADPCMConversionWarning();
                byte[] brstm_temp = FSTMConverter.ToRSTM((FSTMHeader *)Header);
                fixed(byte *ptr = brstm_temp)
                {
                    ReplaceRaw(ptr, brstm_temp.Length);
                    return(false);
                }
            }

            StrmDataInfo *part1 = Header->HEADData->Part1;

            _encoding   = part1->_format._encoding;
            _channels   = part1->_format._channels;
            _looped     = part1->_format._looped != 0;
            _sampleRate = part1->_sampleRate;
            _loopStart  = part1->_loopStartSample;
            _numSamples = part1->_numSamples;
            _dataOffset = part1->_dataOffset;
            _numBlocks  = part1->_numBlocks;
            _blockSize  = part1->_blockSize;
            _bps        = part1->_bitsPerSample;

            int offset = Header->DATAData->Data - Header;

            if (offset < WorkingUncompressed.Length)
            {
                _audioSource = new DataSource(Header->DATAData->Data, WorkingUncompressed.Length - offset);
                SetSizeInternal(offset);
            }

            return(false);
        }
        public static ADPCMStream[] GetStreams(RSTMHeader* pRSTM, VoidPtr dataAddr)
        {
            HEADHeader* pHeader = pRSTM->HEADData;
            StrmDataInfo* part1 = pHeader->Part1;
            int c = part1->_format._channels;
            ADPCMStream[] streams = new ADPCMStream[c.RoundUpToEven() / 2];

            for (int i = 0; i < streams.Length; i++)
            {
                int x = (i + 1) * 2 <= c ? 2 : 1;
                streams[i] = new ADPCMStream(pRSTM, x, i * 2, dataAddr);
            }

            return streams;
        }
Пример #5
0
        public IAudioStream[] CreateStreams()
        {
            if (Header == null)
            {
                return(null);
            }
            StrmDataInfo *info = Header->HEADData->Part1;

            if (Header != null)
            {
                switch ((WaveEncoding)info->_format._encoding)
                {
                case WaveEncoding.ADPCM:
                    return(ADPCMStream.GetStreams(Header, _audioSource.Address));

                case WaveEncoding.PCM16:
                    return(PCMStream.GetStreams(Header, _audioSource.Address));
                }
            }
            return(new IAudioStream[] { null });
        }
Пример #6
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;

            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);
        }
    }
Пример #7
0
        public static unsafe FileMap Encode(IAudioStream stream, IProgressTracker progress, WaveEncoding encoding = WaveEncoding.ADPCM)
#endif
        {
            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 samplesPerBlock = encoding == WaveEncoding.ADPCM ? 0x3800
                : encoding == WaveEncoding.PCM16 ? 0x1000
                : 0;

            if (samplesPerBlock == 0)
            {
                throw new ArgumentException("Encoding must be ADPCM or PCM16");
            }

            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 % samplesPerBlock) != 0)
                {
                    loopPadding = samplesPerBlock - 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 + samplesPerBlock - 1) / samplesPerBlock;

            //Initialize stream info
            if ((tmp = totalSamples % samplesPerBlock) != 0)
            {
                lbSamples = tmp;
                if (encoding == WaveEncoding.ADPCM)
                {
                    lbSize = (lbSamples + 13) / 14 * 8;
                }
                else if (encoding == WaveEncoding.PCM16)
                {
                    lbTotal = lbSize = lbSamples * 2;
                }
                else if (encoding == WaveEncoding.PCM8)
                {
                    lbTotal = lbSize = lbSamples;
                }
                else
                {
                    throw new NotImplementedException();
                }
                lbTotal = lbSize.Align(0x20);
            }
            else
            {
                lbSamples = samplesPerBlock;
                lbTotal   = lbSize = 0x2000;
            }

            //Get section sizes
            int rstmSize = 0x40;
            int headSize = (0x68 + (channels * (encoding == WaveEncoding.ADPCM ? 0x40 : 0x10))).Align(0x20);
            int adpcSize = encoding == WaveEncoding.ADPCM
                ? ((blocks - 1) * 4 * channels + 0x10).Align(0x20)
                : 0;
            int dataSize = ((blocks - 1) * 0x2000 + lbTotal) * channels + 0x20;

#if RSTMLIB
            //Create byte array
            byte[] array = new byte[rstmSize + headSize + adpcSize + dataSize];
            fixed(byte *address = array)
            {
#else
            //Create file map
            FileMap map     = FileMap.FromTempFile(rstmSize + headSize + adpcSize + dataSize);
            VoidPtr address = map.Address;
#endif

                //Get section pointers
                RSTMHeader *    rstm = (RSTMHeader *)address;
                HEADHeader *    head = (HEADHeader *)((byte *)rstm + rstmSize);
                ADPCHeader *    adpc = (ADPCHeader *)((byte *)head + headSize);
                RSTMDATAHeader *data = (RSTMDATAHeader *)((byte *)adpc + adpcSize);

                //Initialize sections
                rstm->Set(headSize, adpcSize, dataSize);
                head->Set(headSize, channels, encoding);
                if (adpcSize > 0)
                {
                    adpc->Set(adpcSize);
                }
                data->Set(dataSize);

                //Set HEAD data
                StrmDataInfo *part1 = head->Part1;
                part1->_format            = new AudioFormatInfo((byte)encoding, (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   = samplesPerBlock;
                part1->_lastBlockSize     = lbSize;
                part1->_lastBlockSamples  = lbSamples;
                part1->_lastBlockTotal    = lbTotal;
                part1->_dataInterval      = encoding == WaveEncoding.ADPCM ? samplesPerBlock : 0;
                part1->_bitsPerSample     = encoding == WaveEncoding.ADPCM ? 4 : 0;

                if (encoding == WaveEncoding.ADPCM)
                {
                    //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 x = 0; x < channels; x++)
                    {
                        *pyn++ = 0;
                        *pyn++ = 0;
                    }

                    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++)
                        {
                            short *sPtr = channelBuffers[x] + sIndex;

                            //Set block yn values
                            if (bIndex != blocks)
                            {
                                *pyn++ = sPtr[samplesPerBlock + 1];
                                *pyn++ = 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 += 0x2000;
                            }
                        }

                        if (progress != null)
                        {
                            if ((sIndex % samplesPerBlock) == 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 / samplesPerBlock;
                        int loopChunk = (loopStart - (loopBlock * samplesPerBlock)) / 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]);
                    }
                }
                else if (encoding == WaveEncoding.PCM16)
                {
                    bshort *destPtr = (bshort *)data->Data;
                    for (int i = 0; i < blocks; i++)
                    {
                        int samplesPerChannel = i < blocks - 1
                        ? part1->_samplesPerBlock
                        : part1->_lastBlockSamples;
                        int bytesPerChannel = i < blocks - 1
                        ? part1->_blockSize
                        : part1->_lastBlockTotal;
                        short[] sampleData = new short[channels * bytesPerChannel / sizeof(short)];

                        fixed(short *sampleDataPtr = sampleData)
                        {
                            int read = 0;

                            do
                            {
                                if (stream.SamplePosition == stream.LoopEndSample && looped)
                                {
                                    stream.SamplePosition = stream.LoopStartSample;
                                }
                                int s = stream.ReadSamples(sampleDataPtr + read, samplesPerChannel - read);
                                if (s == 0)
                                {
                                    throw new Exception("No samples could be read from the stream");
                                }
                                read += s;
                            }while (read < samplesPerChannel);
                        }

                        for (int j = 0; j < channels; j++)
                        {
                            for (int k = j; k < sampleData.Length; k += channels)
                            {
                                *(destPtr++) = sampleData[k];
                            }
                        }

                        progress.Update(progress.CurrentValue + (samplesPerChannel * channels * 3));
                    }
                }

                if (progress != null)
                {
                    progress.Finish();
                }

#if RSTMLIB
            }

            return(array);
#else
                return(map);
#endif
        }
Пример #8
0
        internal PCMStream(RSTMHeader *header, int channels, int startChannel, void *audioSource)
        {
            StrmDataInfo *info = header->HEADData->Part1;

            if (channels > 2)
            {
                throw new NotImplementedException("Cannot load PCM16 audio with more than 2 channels");
            }
            if (info->_format._channels < channels)
            {
                throw new Exception("Not enough channels");
            }

            int size = info->_numSamples * channels * sizeof(short);

            _allocatedHGlobal = Marshal.AllocHGlobal(size);

            byte *fromL = (byte *)audioSource;
            byte *fromR = fromL;
            byte *to    = (byte *)_allocatedHGlobal;

            bool stereo = channels == 2;

            for (int block = 0; block < info->_numBlocks; block++)
            {
                int bs = (block == info->_numBlocks - 1)
                    ? info->_lastBlockSize
                    : info->_blockSize;

                if (block == 0)
                {
                    fromL += (bs * startChannel);
                    fromR += (bs * startChannel);
                }
                else
                {
                    fromL += bs * (info->_format._channels - channels);
                    fromR += bs * (info->_format._channels - channels);
                }

                if (stereo)
                {
                    fromR += bs;
                }
                for (int i = 0; i < bs; i += 2)
                {
                    to[0]  = fromL[1];
                    to[1]  = fromL[0];
                    fromL += 2;
                    to    += 2;
                    if (stereo)
                    {
                        to[0]  = fromR[1];
                        to[1]  = fromR[0];
                        fromR += 2;
                        to    += 2;
                    }
                }
                if (stereo)
                {
                    fromL += bs;
                }
            }

            _bps         = 16;
            _numChannels = channels;
            _frequency   = info->_sampleRate;
            _numSamples  = info->_numSamples;

            _source    = (short *)_allocatedHGlobal;
            _samplePos = 0;

            _looped    = info->_format._looped != 0;
            _loopStart = info->_loopStartSample;
            _loopEnd   = _numSamples;
        }
        internal PCMStream(RSTMHeader *header, int channels, int startChannel, void *audioSource)
        {
            StrmDataInfo *info = header->HEADData->Part1;

            if (info->_format._channels < startChannel + channels)
            {
                throw new Exception("Not enough channels");
            }

            List <short[]>[] blocksByChannel = new List <short[]> [info->_format._channels];
            for (int i = 0; i < blocksByChannel.Length; i++)
            {
                blocksByChannel[i] = new List <short[]>();
            }

            byte *from = (byte *)audioSource;

            for (int block = 0; block < info->_numBlocks; block++)
            {
                int blockSize = (block == info->_numBlocks - 1)
                    ? info->_lastBlockSize
                    : info->_blockSize;
                int blockTotal = (block == info->_numBlocks - 1)
                    ? info->_lastBlockTotal
                    : info->_blockSize;

                for (int channel = 0; channel < info->_format._channels; channel++)
                {
                    short[] b = new short[blockSize / sizeof(short)];
                    Marshal.Copy((IntPtr)from, b, 0, b.Length);
                    from += blockTotal;
                    blocksByChannel[channel].Add(b);
                }
            }

            List <List <short[]> > blocksToUseByChannel = new List <List <short[]> >();

            for (int i = 0; i < channels; i++)
            {
                blocksToUseByChannel.Add(blocksByChannel[startChannel + i]);
            }

            int size = info->_numSamples * channels * sizeof(short);

            //int size2 = blocksToUseByChannel.SelectMany(blocks => blocks.Select(block => block.Length)).Sum() * sizeof(short);
            //if (size != size2)
            //{
            //    throw new Exception($"{size} != {size2}");
            //}

            _allocatedHGlobal = Marshal.AllocHGlobal(size);
            short *toPtr = (short *)_allocatedHGlobal;
            //short* endPtr = (short*)(_allocatedHGlobal + size);
            int blockCount = blocksToUseByChannel.Select(b => b.Count).Distinct().Single();

            for (int blockIndex = 0; blockIndex < blockCount; blockIndex++)
            {
                List <short[]> blocks      = blocksToUseByChannel.Select(l => l[blockIndex]).ToList();
                int            blockShorts = blocks.Select(a => a.Length).Distinct().Single();
                for (int i = 0; i < blockShorts; i++)
                {
                    foreach (short[] block in blocks)
                    {
                        *toPtr++ = block[i].Reverse();
                    }
                }
            }
            //if (toPtr != endPtr) throw new Exception($"Not all data filled ({(long)_allocatedHGlobal}, {(long)toPtr}, {(long)endPtr})");

            _bps         = 16;
            _numChannels = channels;
            _frequency   = info->_sampleRate;
            _numSamples  = info->_numSamples;

            _source    = (short *)_allocatedHGlobal;
            _samplePos = 0;

            _looped    = info->_format._looped != 0;
            _loopStart = info->_loopStartSample;
            _loopEnd   = _numSamples;
        }