Exemplo n.º 1
0
        public static byte[] wavToDPCMByte(byte[] data, uint dpcm_enc_lookahead = 3, bool loopEnabled = false, int loopStart = 0, int loopEnd = 0)
        {
            List <byte> wave = new List <byte>();

            if (data[0] != 'R' ||
                data[1] != 'I' ||
                data[2] != 'F' ||
                data[3] != 'F'
                )
            {
                R.ShowStopError("Waveファイルではありません. RIFFヘッダがありません");
                return(null);
            }
            if (data.Length < (44 + 1))
            {
                R.ShowStopError("Waveファイルではありません. データが小さすぎます");
                return(null);
            }

            uint riff_chunk_size      = U.u32(data, 4);
            uint riff_form_type       = U.u32(data, 8);
            uint fmt_chunk_ID         = U.u32(data, 12);
            uint fmt_chunk_size       = U.u32(data, 16);
            uint fmt_wave_format_type = U.u16(data, 20);
            uint fmt_channel          = U.u16(data, 32);
            uint fmt_samples_per_sec  = U.u32(data, 24);
            uint fmt_bytes_per_sec    = U.u32(data, 28);
            uint fmt_block_size       = U.u16(data, 32);
            uint fmt_bits_per_sample  = U.u16(data, 34);
            uint data_chunk_ID        = U.u32(data, 36);
            uint data_chunk_size      = U.u32(data, 40);

            if (data_chunk_size > data.Length - (44))
            {//チャンクのデータサイズが不正だったら修正する.
                data_chunk_size = (uint)(data.Length - (44));
            }
            if (data_chunk_size <= 1)
            {
                R.ShowStopError("Waveファイルではありません. data_chunk_size({0})が小さすぎます", data_chunk_size);
                return(null);
            }

            PatchUtil.ImprovedSoundMixer withImprovedSoundMixer = PatchUtil.SearchImprovedSoundMixer();
            if (fmt_bits_per_sample > 8)
            {//サンプルビット数が8ビットを超える
                R.ShowStopError("Waveファイルが高音質すぎます。{0}bit\r\n品質は、8bit 12khz monoぐらいにしてください。", fmt_bits_per_sample);
                return(null);
            }

            U.append_u32(wave, 0x01);                       //圧縮フラグ 0x01 00 00 00
            U.append_u32(wave, fmt_samples_per_sec * 1024); //周波数*1024
            U.append_u32(wave, 0);                          //不明
            U.append_u32(wave, data_chunk_size);            //元のデータ長

            if (loopEnabled)
            {
                if (loopEnd > data_chunk_size)
                {
                    loopEnd = (int)data_chunk_size;
                }
            }
            else
            {//ループしない場合終端になります
                loopEnd = (int)data_chunk_size;
            }

            int loop_sample = 0;

            for (uint i = 0; i < loopEnd; i += DPCM_BLK_SIZE)
            {
                uint   waveDataI = 44 + i;
                byte[] wavBin    = U.getBinaryData(data, waveDataI, DPCM_BLK_SIZE);
                int[]  ds        = Add0x80(wavBin);

                // check if loop end is inside this block
                if (i + DPCM_BLK_SIZE > loopEnd)
                {
                    Debug.Assert(loopEnd - i < DPCM_BLK_SIZE);
                    ds[loopEnd - i] = (byte)loop_sample;
                }
                // TODO apply dither noise
                int s = ds[0];
                if (loopEnabled && i == loopStart)
                {
                    loop_sample = s;
                }

                U.append_u8(wave, (byte)(s & 0xFF));
                //data_write(ofs, block_pos, s, false);

                uint innerLoopCount = 1;
                byte outData        = 0;
                while (innerLoopCount < DPCM_BLK_SIZE)
                {
                    uint sampleBufReadLen = Math.Min(dpcm_enc_lookahead, DPCM_BLK_SIZE - innerLoopCount);
                    int  minimumError;
                    uint minimumErrorIndex;
                    if (innerLoopCount != 1)
                    {//どういうわけか、最初の1バイトは特殊な格納方法をする
                        dpcm_lookahead(
                            out minimumError, out minimumErrorIndex,
                            ds, innerLoopCount, sampleBufReadLen, s);
                        outData         = (byte)((minimumErrorIndex & 0xF) << 4);
                        s              += dpcmLookupTable[minimumErrorIndex];
                        innerLoopCount += 1;
                    }

                    sampleBufReadLen = Math.Min(dpcm_enc_lookahead, DPCM_BLK_SIZE - innerLoopCount);
                    dpcm_lookahead(
                        out minimumError, out minimumErrorIndex,
                        ds, innerLoopCount, sampleBufReadLen, s);
                    outData        |= (byte)(minimumErrorIndex & 0xF);
                    s              += dpcmLookupTable[minimumErrorIndex];
                    innerLoopCount += 1;

                    U.append_u8(wave, (byte)(outData & 0xFF));
                    //data_write(ofs, block_pos, outData, true);
                }
            }

            return(wave.ToArray());
        }