public static void LoadData <T>( this INativeAudioBuffer buffer, int sampleRate, T[] data, int dataLength, AudioDataLayout dataLayout, AudioDataElementType dataElementType) where T : struct { if (dataLength < 0) { throw new ArgumentOutOfRangeException("dataLength", "Data length cannot be negative"); } if (dataLength > data.Length) { throw new ArgumentOutOfRangeException("dataLength", "Data length cannot exceed the specified arrays length."); } int itemSize = Marshal.SizeOf(typeof(T)); using (PinnedArrayHandle pinned = new PinnedArrayHandle(data)) { buffer.LoadData( sampleRate, pinned.Address, itemSize * dataLength, dataLayout, dataElementType); } }
void INativeAudioBuffer.LoadData(int sampleRate, IntPtr data, int size, AudioDataLayout dataLayout, AudioDataElementType dataElementType) { ALFormat format = ALFormat.Mono16; if (dataLayout == AudioDataLayout.Mono) { if (dataElementType == AudioDataElementType.Byte) { format = ALFormat.Mono8; } else if (dataElementType == AudioDataElementType.Short) { format = ALFormat.Mono16; } } else if (dataLayout == AudioDataLayout.LeftRight) { if (dataElementType == AudioDataElementType.Byte) { format = ALFormat.Stereo8; } else if (dataElementType == AudioDataElementType.Short) { format = ALFormat.Stereo16; } } AL.BufferData( this.handle, format, data, (int)size, sampleRate); }
void INativeAudioBuffer.LoadData <T>(int sampleRate, T[] data, int dataLength, AudioDataLayout dataLayout, AudioDataElementType dataElementType) { ALFormat format = ALFormat.Mono16; if (dataLayout == AudioDataLayout.Mono) { if (dataElementType == AudioDataElementType.Byte) { format = ALFormat.Mono8; } else if (dataElementType == AudioDataElementType.Short) { format = ALFormat.Mono16; } } else if (dataLayout == AudioDataLayout.LeftRight) { if (dataElementType == AudioDataElementType.Byte) { format = ALFormat.Stereo8; } else if (dataElementType == AudioDataElementType.Short) { format = ALFormat.Stereo16; } } int sizeOfElement = System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)); AL.BufferData( this.handle, format, data, dataLength * sizeOfElement, sampleRate); }
void INativeAudioBuffer.LoadData(int sampleRate, IntPtr data, int size, AudioDataLayout dataLayout, AudioDataElementType dataElementType) { }
unsafe void INativeAudioBuffer.LoadData <T>(int sampleRate, T[] data, int dataLength, AudioDataLayout dataLayout, AudioDataElementType dataElementType) { float pitch = (float)sampleRate / targetSampleRate; int targetLengthPerChannel = (int)Math.Ceiling(dataLength / pitch); // ToDo: Resampler skips samples with too high input sample rate (and too low output sample rate), // but that almost never happens on Android anyway GCHandle gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned); try { if (dataLayout == AudioDataLayout.Mono) { // Duplicate mono input to stereo output ResizeBuffer(targetLengthPerChannel * 2); if (dataElementType == AudioDataElementType.Byte) { // Duplicate channel, resample and convert 8-bit samples to 16-bit samples byte *ptr = (byte *)gcHandle.AddrOfPinnedObject(); for (int destIndex = 0; destIndex < targetLengthPerChannel; destIndex++) { float srcIndex = (float)destIndex / targetLengthPerChannel * dataLength; short sample1 = (short)((ptr[(int)srcIndex] - 0x80) << 8); short sample2 = (short)((ptr[Math.Min((int)srcIndex + 1, dataLength - 1)] - 0x80) << 8); short sample = (short)(sample1 + (sample2 - sample1) * (srcIndex % 1f)); InternalBuffer[Length++] = sample; InternalBuffer[Length++] = sample; } } else if (dataElementType == AudioDataElementType.Short) { // Duplicate channel and resample short *ptr = (short *)gcHandle.AddrOfPinnedObject(); for (int destIndex = 0; destIndex < targetLengthPerChannel; destIndex++) { float srcIndex = (float)destIndex / targetLengthPerChannel * dataLength; short sample1 = ptr[(int)srcIndex]; short sample2 = ptr[Math.Min((int)srcIndex + 1, dataLength - 1)]; short sample = (short)(sample1 + (sample2 - sample1) * (srcIndex % 1f)); InternalBuffer[Length++] = sample; InternalBuffer[Length++] = sample; } } } else if (dataLayout == AudioDataLayout.LeftRight) { // Channels are already interleaved, "targetLengthPerChannel" will // be divided by channel count later, it's target length right here ResizeBuffer(targetLengthPerChannel); if (dataElementType == AudioDataElementType.Byte) { byte *ptr = (byte *)gcHandle.AddrOfPinnedObject(); if (targetSampleRate == sampleRate) { // Resampling is not needed, convert 8-bit samples to 16-bit samples for (int srcIndex = 0; srcIndex < dataLength; srcIndex++) { short sample = (short)((ptr[srcIndex] - 0x80) << 8); InternalBuffer[Length++] = sample; } } else { // Resample and convert samples to 16-bit samples targetLengthPerChannel /= 2; int dataLengthPerChannel = dataLength / 2; for (int destIndex = 0; destIndex < targetLengthPerChannel; destIndex++) { float srcIndex = (float)destIndex / targetLengthPerChannel * dataLengthPerChannel; short sample1 = (short)((ptr[(int)srcIndex] - 0x80) << 8); short sample2 = (short)((ptr[Math.Min((int)srcIndex + 2, dataLength - 2)] - 0x80) << 8); short sample = (short)(sample1 + (sample2 - sample1) * (srcIndex % 1f)); InternalBuffer[Length++] = sample; sample1 = (short)((ptr[(int)srcIndex + 1] - 0x80) << 8); sample2 = (short)((ptr[Math.Min((int)srcIndex + 3, dataLength - 1)] - 0x80) << 8); sample = (short)(sample1 + (sample2 - sample1) * (srcIndex % 1f)); InternalBuffer[Length++] = sample; } } } else if (dataElementType == AudioDataElementType.Short) { short *ptr = (short *)gcHandle.AddrOfPinnedObject(); if (targetSampleRate == sampleRate) { // Resampling is not needed for (int srcIndex = 0; srcIndex < dataLength; srcIndex++) { InternalBuffer[Length++] = ptr[srcIndex]; } } else { // Resample buffer to target sample rate targetLengthPerChannel /= 2; int dataLengthPerChannel = dataLength / 2; for (int destIndex = 0; destIndex < targetLengthPerChannel; destIndex++) { float srcIndex = (float)destIndex / targetLengthPerChannel * dataLengthPerChannel; short sample1 = ptr[(int)srcIndex]; short sample2 = ptr[Math.Min((int)srcIndex + 2, dataLength - 2)]; short sample = (short)(sample1 + (sample2 - sample1) * (srcIndex % 1f)); InternalBuffer[Length++] = sample; sample1 = ptr[(int)srcIndex + 1]; sample2 = ptr[Math.Min((int)srcIndex + 3, dataLength - 1)]; sample = (short)(sample1 + (sample2 - sample1) * (srcIndex % 1f)); InternalBuffer[Length++] = sample; } } } } } finally { gcHandle.Free(); } }
void INativeAudioBuffer.LoadData <T>(int sampleRate, T[] data, int dataLength, AudioDataLayout dataLayout, AudioDataElementType dataElementType) { }
//private byte[] buffer; //private int sampleRate; //private AudioDataLayout layout; //private AudioDataElementType type; public static void Parse(byte[] audioData, out byte[] buffer, out int sampleRate, out AudioDataLayout layout, out AudioDataElementType type) { MemoryStream s = new MemoryStream(audioData, true); using (BinaryReader r = new BinaryReader(s, Encoding.ASCII, true)) { uint riff = r.ReadUInt32(); if (riff != 0x46464952) { throw new NotSupportedException(); } uint riffChunkSize = r.ReadUInt32(); uint wave = r.ReadUInt32(); if (wave != 0x45564157) { throw new NotSupportedException(); } uint fmt = r.ReadUInt32(); if (fmt != 0x20746d66) { throw new NotSupportedException(); } uint fmtChunkSize = r.ReadUInt32(); ushort format = r.ReadUInt16(); if (format != 0x1 /*CODEC_PCM*/) { throw new NotSupportedException(); } ushort channels = r.ReadUInt16(); sampleRate = r.ReadInt32(); uint byteRate = r.ReadUInt32(); ushort blockAlign = r.ReadUInt16(); ushort bits = r.ReadUInt16(); if (channels == 2) { layout = AudioDataLayout.LeftRight;; } else if (channels == 1) { layout = AudioDataLayout.Mono; } else { throw new NotSupportedException("Unsupported channels " + channels); } if (bits == 8) { type = AudioDataElementType.Byte; } else if (bits == 16) { type = AudioDataElementType.Short; } else { throw new NotSupportedException("Unsupported bits " + bits); } uint data = r.ReadUInt32(); if (data != 0x61746164) { throw new NotSupportedException(); } int dataChunkSize = r.ReadInt32(); buffer = r.ReadBytes(dataChunkSize); } }