Beispiel #1
0
        // Reference: https://wiki.multimedia.cx/index.php/Microsoft_ADPCM

        public ISound Decode(ReadOnlySpan <byte> data, IWaveFormat fmtChunk, MicrosoftAdpcmFormat microsoftAdpcmFormat)
        {
            var channels = fmtChunk.Channels;
            var channelSamplesPerFrame = microsoftAdpcmFormat.SamplesPerBlock;
            var buffer    = new float[channelSamplesPerFrame];
            var frameSize = fmtChunk.BlockAlign;
            var max       = data.Length / frameSize * frameSize;
            var output    = Enumerable.Range(0, channels).Select(i => new List <float>()).ToArray();

            // Apply coefficients
            var coefficients =
                new int[Math.Max(MicrosoftAdpcmConstants.DefaultCoefficients.Length, microsoftAdpcmFormat.Coefficients.Length)].AsMemory();

            MicrosoftAdpcmConstants.DefaultCoefficients.AsSpan().CopyTo(coefficients.Span);
            microsoftAdpcmFormat.Coefficients.AsSpan().CopyTo(coefficients.Span);

            for (var offset = 0; offset < max; offset += frameSize)
            {
                var mem = data.Slice(offset, frameSize);
                for (var channel = 0; channel < channels; channel++)
                {
                    DecodeFrame(mem, buffer, channel, channels, coefficients.Span);
                    output[channel].AddRange(buffer);
                }
            }

            return(new Sound
            {
                Samples = output.Select(s => new Sample {
                    Data = s
                }).Cast <ISample>().ToList()
            });
        }
Beispiel #2
0
        public IRiffContainer Encode(ISound sound, int samplesPerBlock)
        {
            var sampleRate = sound[NumericData.Rate];

            if (sampleRate == null)
            {
                var sampleRates = sound
                                  .Samples
                                  .Select(s => s[NumericData.Rate])
                                  .Where(r => r != null)
                                  .Distinct()
                                  .ToArray();
                sampleRate = sampleRates.SingleOrDefault();
            }

            if (sampleRate == null)
            {
                sampleRate = 44100;
            }

            var channels = sound.Samples.Count;
            var byteRate = sampleRate * channels * 2 / 4;  //not accurate but not far off

            var container = new RiffContainer
            {
                Format = "WAVE",
                Chunks = new List <IRiffChunk>()
            };

            var extraFormat = new MicrosoftAdpcmFormat
            {
                Coefficients    = MicrosoftAdpcmConstants.DefaultCoefficients,
                SamplesPerBlock = 500
            };

            var format = new RiffFormat
            {
                Format        = 2,
                SampleRate    = (int)sampleRate,
                Channels      = channels,
                ByteRate      = (int)byteRate,
                BitsPerSample = 4,
                BlockAlign    = _microsoftAdpcmEncoder.GetBlockSize(samplesPerBlock, channels),
                ExtraData     = extraFormat.ToBytes()
            };

            container.Chunks.Add(_formatEncoder.Encode(format));
            container.Chunks.Add(new RiffChunk
            {
                Id   = "data",
                Data = _microsoftAdpcmEncoder.Encode(sound, samplesPerBlock)
            });

            return(container);
        }
Beispiel #3
0
        public ISound Decode(Stream stream)
        {
            var riff = _riffStreamReader.Read(stream);

            if (riff.Format != "WAVE")
            {
                throw new RhythmCodexException("RIFF type must be WAVE.");
            }

            var fmt = riff.Chunks.FirstOrDefault(c => c.Id == "fmt ");

            if (fmt == null)
            {
                throw new RhythmCodexException("RIFF must contain the fmt chunk.");
            }
            var format = _waveFmtDecoder.Decode(fmt);

            var data = riff.Chunks.FirstOrDefault(c => c.Id == "data");

            if (data == null)
            {
                throw new RhythmCodexException("RIFF must contain the data chunk.");
            }

            var result = new Sound
            {
                [NumericData.Rate] = format.SampleRate,
                Samples            = new List <ISample>()
            };

            switch (format.Format)
            {
            case 0x0001:     // raw PCM
            {
                float[] decoded;
                switch (format.BitsPerSample)
                {
                case 8:
                    decoded = _pcmDecoder.Decode8Bit(data.Data);
                    break;

                case 16:
                    decoded = _pcmDecoder.Decode16Bit(data.Data);
                    break;

                case 24:
                    decoded = _pcmDecoder.Decode24Bit(data.Data);
                    break;

                case 32:
                    decoded = _pcmDecoder.Decode32Bit(data.Data);
                    break;

                default:
                    throw new RhythmCodexException("Invalid bits per sample.");
                }

                foreach (var channel in decoded.Deinterleave(1, format.Channels))
                {
                    result.Samples.Add(new Sample
                        {
                            [NumericData.Rate] = format.SampleRate,
                            Data = channel
                        });
                }

                break;
            }

            case 0x0002:     // Microsoft ADPCM
            {
                var exFormat = new MicrosoftAdpcmFormat(format.ExtraData);
                var decoded  = _microsoftAdpcmDecoder.Decode(data.Data.AsSpan(), format, exFormat);

                foreach (var sample in decoded.Samples)
                {
                    result.Samples.Add(sample);
                }

                break;
            }

            case 0x0003:     // 32-bit float
            {
                var decoded = _pcmDecoder.DecodeFloat(data.Data);

                foreach (var channel in decoded.Deinterleave(1, format.Channels))
                {
                    result.Samples.Add(new Sample
                        {
                            [NumericData.Rate] = format.SampleRate,
                            Data = channel
                        });
                }

                break;
            }

            case 0x0011:     // IMA ADPCM
            {
                var exFormat = new ImaAdpcmFormat(format.ExtraData);
                var decoded  = _imaAdpcmDecoder.Decode(new ImaAdpcmChunk
                    {
                        Channels = format.Channels,
                        Rate     = format.SampleRate,
                        Data     = data.Data,
                        ChannelSamplesPerFrame = exFormat.SamplesPerBlock
                    });

                foreach (var sample in decoded.SelectMany(s => s.Samples))
                {
                    result.Samples.Add(sample);
                }

                break;
            }
            }

            return(result);
        }