public void AlignedAdpcmIsCorrect(int multiple, int loopStart, int sineCycles, int tolerance) { int loopEnd = sineCycles * 4 * SamplesPerFrame + loopStart; short[] pcm = GenerateSineWave(GetNextMultiple(loopEnd, SamplesPerFrame), 1, SamplesPerFrame * 4); short[] coefs = GcAdpcmCoefficients.CalculateCoefficients(pcm); byte[] adpcm = GcAdpcmEncoder.Encode(pcm, coefs); var alignment = new GcAdpcmAlignment(multiple, loopStart, loopEnd, adpcm, coefs); short[] pcmAligned = GcAdpcmDecoder.Decode(alignment.AdpcmAligned, coefs, new GcAdpcmParameters { SampleCount = alignment.SampleCountAligned }); short[] pcmExpected = GenerateSineWave(alignment.SampleCountAligned, 1, SamplesPerFrame * 4); var diff = new double[alignment.SampleCountAligned]; //Skip the first sine cycle and last ADPCM frame due to history samples int end = GetNextMultiple(alignment.SampleCountAligned, SamplesPerFrame) - SamplesPerFrame; for (int i = SamplesPerFrame * 4; i < end; i++) { double dist = Math.Abs(pcmExpected[i] - pcmAligned[i]); diff[i] = dist; } Assert.All(diff, x => Assert.InRange(x, 0, tolerance)); }
/// <summary> /// Wraps the decoded DSP data into a WAVE file stored as a byte array /// </summary> /// <returns></returns> public byte[] ToWAVE() { using (var stream = new MemoryStream()) { using (BinaryWriter w = new BinaryWriter(stream)) { w.Write("RIFF".ToCharArray()); w.Write(0); // wave size w.Write("WAVE".ToCharArray()); short BitsPerSample = 16; var byteRate = Frequency * Channels.Count * BitsPerSample / 8; short blockAlign = (short)(Channels.Count * BitsPerSample / 8); w.Write("fmt ".ToCharArray()); w.Write(16); // chunk size w.Write((short)1); // compression w.Write((short)Channels.Count); w.Write(Frequency); w.Write(byteRate); w.Write(blockAlign); w.Write(BitsPerSample); w.Write("data".ToCharArray()); var subchunkOffset = w.BaseStream.Position; w.Write(0); int subChunkSize = 0; if (Channels.Count == 1) { short[] sound_data = GcAdpcmDecoder.Decode(Channels[0].Data, Channels[0].COEF); subChunkSize += sound_data.Length * 2; foreach (var s in sound_data) { w.Write(s); } } if (Channels.Count == 2) { short[] sound_data1 = GcAdpcmDecoder.Decode(Channels[0].Data, Channels[0].COEF); short[] sound_data2 = GcAdpcmDecoder.Decode(Channels[1].Data, Channels[1].COEF); subChunkSize += (sound_data1.Length + sound_data2.Length) * 2; for (int i = 0; i < sound_data1.Length; i++) { w.Write(sound_data1[i]); w.Write(sound_data2[i]); } } w.BaseStream.Position = subchunkOffset; w.Write(subChunkSize); w.BaseStream.Position = 4; w.Write((int)(w.BaseStream.Length - 8)); } return(stream.ToArray()); } }
public GcAdpcmAlignment(int multiple, int loopStart, int loopEnd, byte[] adpcm, short[] coefs) { AlignmentMultiple = multiple; LoopStart = loopStart; LoopEnd = loopEnd; AlignmentNeeded = !Helpers.LoopPointsAreAligned(loopStart, multiple); if (!AlignmentNeeded) { return; } int loopLength = loopEnd - loopStart; LoopStartAligned = Helpers.GetNextMultiple(loopStart, multiple); SampleCountAligned = loopEnd + (LoopStartAligned - loopStart); AdpcmAligned = new byte[SampleCountToByteCount(SampleCountAligned)]; PcmAligned = new short[SampleCountAligned]; int framesToKeep = loopEnd / SamplesPerFrame; int bytesToKeep = framesToKeep * BytesPerFrame; int samplesToKeep = framesToKeep * SamplesPerFrame; int samplesToEncode = SampleCountAligned - samplesToKeep; var param = new GcAdpcmParameters { SampleCount = loopEnd }; short[] oldPcm = GcAdpcmDecoder.Decode(adpcm, coefs, param); Array.Copy(oldPcm, 0, PcmAligned, 0, loopEnd); var newPcm = new short[samplesToEncode]; Array.Copy(oldPcm, samplesToKeep, newPcm, 0, loopEnd - samplesToKeep); for (int currentSample = loopEnd - samplesToKeep; currentSample < samplesToEncode; currentSample += loopLength) { Array.Copy(PcmAligned, loopStart, newPcm, currentSample, Math.Min(loopLength, samplesToEncode - currentSample)); } param.SampleCount = samplesToEncode; param.History1 = samplesToKeep < 1 ? (short)0 : oldPcm[samplesToKeep - 1]; param.History2 = samplesToKeep < 2 ? (short)0 : oldPcm[samplesToKeep - 2]; byte[] newAdpcm = GcAdpcmEncoder.Encode(newPcm, coefs, param); Array.Copy(adpcm, 0, AdpcmAligned, 0, bytesToKeep); Array.Copy(newAdpcm, 0, AdpcmAligned, bytesToKeep, newAdpcm.Length); short[] decodedPcm = GcAdpcmDecoder.Decode(newAdpcm, coefs, param); Array.Copy(decodedPcm, 0, PcmAligned, samplesToKeep, samplesToEncode); }
public void AlignedPcmIsCorrect(int multiple, int loopStart, int sineCycles) { int loopEnd = sineCycles * 4 * SamplesPerFrame + loopStart; var pcm = GenerateSineWave(GetNextMultiple(loopEnd, SamplesPerFrame), 1, SamplesPerFrame * 4); var coefs = GcAdpcmCoefficients.CalculateCoefficients(pcm); var adpcm = GcAdpcmEncoder.Encode(pcm, coefs); var alignment = new GcAdpcmAlignment(multiple, loopStart, loopEnd, adpcm, coefs); var pcmAligned = alignment.PcmAligned; var pcmExpected = GcAdpcmDecoder.Decode(alignment.AdpcmAligned, coefs, new GcAdpcmParameters { SampleCount = alignment.SampleCountAligned }); Assert.Equal(pcmExpected, pcmAligned); }
private void EnsurePcmDecoded() => AlignedPcm = AlignedPcm ?? GcAdpcmDecoder.Decode(AlignedAdpcm, Coefs, new GcAdpcmParameters { SampleCount = AlignedSampleCount });
public short[] GetPcmAudio() => AlignmentNeeded ? Alignment.PcmAligned : Pcm ?? GcAdpcmDecoder.Decode(GetAdpcmAudio(), Coefs, new GcAdpcmParameters { SampleCount = SampleCount, History1 = StartContext.Hist1, History2 = StartContext.Hist2 });
public short[] DecodeAdpcm(byte[] adpcm, short[] coefs, int sampleCount) { return(GcAdpcmDecoder.Decode(adpcm, coefs, new GcAdpcmParameters { SampleCount = sampleCount })); }