/// <summary> /// Convert the data to floating point PCM. /// </summary> /// <param name="decodingData">Decoding data.</param> /// <returns>Floating point PCM data.</returns> public float[] ToFloatPCM(object decodingData = null) { //Get context. DspAdpcmContext context = null; if (decodingData != null) { context = decodingData as DspAdpcmContext; } if (context == null) { context = Context; } //Decode data. short[] pcm = new short[SampleCount()]; DspAdpcmDecoder.Decode(Data, ref pcm, ref Context, (uint)pcm.Length); var ret = pcm.Select(x => (float)x / short.MaxValue).ToArray(); //Set pointers. decodingData = Context = context; //Return data. return(ret); }
/// <summary> /// Read the file. /// </summary> /// <param name="r">The reader.</param> public override void Read(FileReader r) { //Read data. r.ByteOrder = ByteOrder.BigEndian; uint numSamples = r.ReadUInt32(); r.ReadUInt32(); //Num nibbles. SampleRate = r.ReadUInt32(); Loops = r.ReadUInt16() > 0; r.ReadUInt16(); //DSP-ADPCM is 0. LoopStart = r.ReadUInt32(); LoopEnd = r.ReadUInt32(); r.ReadUInt32(); //Always 2??? DspAdpcmContext context = r.Read <DspAdpcmContext>(); ushort numChannels = r.ReadUInt16(); BlockSize = (uint)(r.ReadUInt16() * 8); Extended = numChannels > 0; //Add channel 0. //Channels = new List<AudioEncoding>(); //Channels.Add(new DspAdpcmOLD() { Context = context }); r.Align(0x60); //Extra channels. for (int i = 1; i < numChannels; i++) { r.ReadBytes(0x1C); //Channels.Add(new DspAdpcmOLD() { Context = r.Read<DspAdpcmContext>() }); r.Align(0x60); } //Do block reading logic. if (numChannels == 0) { numChannels = 1; } long dataLen = r.Length - r.Position; long channelLen = dataLen / numChannels; if (!Extended) { BlockSize = (uint)channelLen; } uint lastBlockSize = (uint)(channelLen % BlockSize); bool blockCarry = false; if (lastBlockSize == 0) { lastBlockSize = BlockSize; } else { blockCarry = true; } uint numBlocks = (uint)(channelLen / BlockSize + (blockCarry ? 1 : 0)); //Read data. //Audio.Read(r, encodingType, numChannels, numBlocks, BlockSize, blockSamples, lastBlockSize, lastBlockSamples, 0); }
/// <summary> /// Decode DSP-ADPCM data. /// </summary> /// <param name="src">DSP-ADPCM source.</param> /// <param name="dst">Destination array of samples.</param> /// <param name="cxt">DSP-APCM context.</param> /// <param name="samples">Number of samples.</param> public static void Decode(byte[] src, ref Int16[] dst, ref DspAdpcmContext cxt, UInt32 samples) { //Each DSP-ADPCM frame is 8 bytes long. It contains 1 header byte, and 7 sample bytes. //Set initial values. short hist1 = cxt.yn1; short hist2 = cxt.yn2; int dstIndex = 0; int srcIndex = 0; //Until all samples decoded. while (dstIndex < samples) { //Get the header. byte header = src[srcIndex++]; //Get scale and co-efficient index. UInt16 scale = (UInt16)(1 << (header & 0xF)); byte coef_index = (byte)(header >> 4); short coef1 = cxt.coefs[coef_index][0]; short coef2 = cxt.coefs[coef_index][1]; //7 sample bytes per frame. for (UInt32 b = 0; b < 7; b++) { //Get byte. byte byt = src[srcIndex++]; //2 samples per byte. for (UInt32 s = 0; s < 2; s++) { sbyte adpcm_nibble = ((s == 0) ? GetHighNibble(byt) : GetLowNibble(byt)); short sample = Clamp16(((adpcm_nibble * scale) << 11) + 1024 + ((coef1 * hist1) + (coef2 * hist2)) >> 11); hist2 = hist1; hist1 = sample; dst[dstIndex++] = sample; if (dstIndex >= samples) { break; } } if (dstIndex >= samples) { break; } } } //Set context. cxt.yn1 = hist1; cxt.yn2 = hist2; }
/// <summary> /// Encodes the samples. /// </summary> /// <returns>The samples.</returns> /// <param name="samples">Samples.</param> public static byte[] EncodeSamples(short[] samples, DspAdpcmContext info, int loopStart) { //Encode data. byte[] dspAdpcm = GcAdpcmEncoder.Encode(samples, info.GetCoeffs(), new GcAdpcmParameters() { History1 = info.yn1, History2 = info.yn2, SampleCount = samples.Length }); //Loop stuff. if (loopStart > 0) { info.loop_yn1 = samples[loopStart - 1]; } if (loopStart > 1) { info.loop_yn2 = samples[loopStart - 2]; } //Return data. return(dspAdpcm); }
/// <summary> /// Convert from floating point PCM to the data. /// </summary> /// <param name="pcm">PCM data.</param> /// <param name="encodingData">Encoding data.</param> /// <param name="loopStart">Loop start.</param> /// <param name="loopEnd">Loop end.</param> public void FromFloatPCM(float[] pcm, object encodingData = null, int loopStart = -1, int loopEnd = -1) { //Convert data. short[] s = pcm.Select(x => ConvertFloat(x)).ToArray(); //Get context. DspAdpcmContext context = null; if (encodingData != null) { context = encodingData as DspAdpcmContext; } if (context == null) { context = new DspAdpcmContext(); context.LoadCoeffs(GcAdpcmCoefficients.CalculateCoefficients(s)); } //Encode data. Data = DspAdpcmEncoder.EncodeSamples(s, context, loopStart); //Set pointers. encodingData = Context = context; }