protected override bool BufferData(Stream baseStream, Queue <byte> data) { if (dataSize <= 0) { return(true); } var chunk = ImaAdpcmChunk.Read(baseStream); for (var n = 0; n < chunk.CompressedSize; n++) { var b = baseStream.ReadUInt8(); var t = ImaAdpcmReader.DecodeImaAdpcmSample(b, ref index, ref currentSample); data.Enqueue((byte)t); data.Enqueue((byte)(t >> 8)); baseOffset += 2; if (baseOffset < outputSize) { /* possible that only half of the final byte is used! */ t = ImaAdpcmReader.DecodeImaAdpcmSample((byte)(b >> 4), ref index, ref currentSample); data.Enqueue((byte)t); data.Enqueue((byte)(t >> 8)); baseOffset += 2; } } dataSize -= 8 + chunk.CompressedSize; return(dataSize <= 0); }
// Reference: https://github.com/dbry/adpcm-xq/blob/master/adpcm-lib.c public IList <ISound> Decode(ImaAdpcmChunk chunk) { var sounds = new List <ISound>(); var buffer = new float[chunk.ChannelSamplesPerFrame]; var channels = chunk.Channels; var frameSize = (chunk.ChannelSamplesPerFrame * chunk.Channels / 2) + (chunk.Channels * 4); var max = (chunk.Data.Length / frameSize) * frameSize; var output = Enumerable.Range(0, channels).Select(i => new List <float>()).ToArray(); for (var offset = 0; offset < max; offset += frameSize) { var mem = chunk.Data.AsSpan(offset, frameSize); for (var channel = 0; channel < channels; channel++) { DecodeFrame(mem, buffer, channel, channels); output[channel].AddRange(buffer); } } sounds.Add(new Sound { Samples = output.Select(s => new Sample { Data = s }).Cast <ISample>().ToList() }); return(sounds); }
public void TestXboxAdpcm() { var decoder = Resolve <IImaAdpcmDecoder>(); var encoder = Resolve <IRiffPcm16SoundEncoder>(); var writer = Resolve <IRiffStreamWriter>(); var data = GetArchiveResource($"ImaAdpcm.RawXboxAdpcm.zip") .First() .Value; var ima = new ImaAdpcmChunk { Channels = 2, ChannelSamplesPerFrame = 64, Data = data, Rate = 44100 }; var decoded = decoder.Decode(ima); var index = 0; foreach (var sound in decoded) { sound[NumericData.Rate] = ima.Rate; var encoded = encoder.Encode(sound); var outfolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "ima"); if (!Directory.Exists(outfolder)) { Directory.CreateDirectory(outfolder); } using (var outStream = new MemoryStream()) { writer.Write(outStream, encoded); outStream.Flush(); File.WriteAllBytes(Path.Combine(outfolder, $"{index:000}.wav"), outStream.ToArray()); index++; } } }