/// <summary> /// Initializes a new instance of the <see cref="WavReader"/> class. /// </summary> public WavReader() { _stream = null; _bytesPerSample = 0; _offsetStart = 0; _offsetEnd = 0; _format = WavFormat.PCM; _ownStream = false; }
/// <summary> /// 写文件 /// </summary> /// <param name="wavFormat">文件格式</param> /// <param name="audioData">音频数据</param> /// <param name="startIndex">audioData数组开始索引位置</param> /// <param name="length">写入audioData数组长度</param> public void WriteWavFile(WavFormat wavFormat, byte[] audioData, int startIndex, int length) { FileStream fs = null; BinaryWriter bw = null; try { fs = new FileStream(_filePath, FileMode.Create, FileAccess.Write); bw = new BinaryWriter(fs); fs.Position = 0; bw.Write(new char[4] { 'R', 'I', 'F', 'F' }); //ChunkFileSize bw.Write((int)(length + 44 - 8)); bw.Write(new char[8] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' }); bw.Write((int)16); bw.Write((short)1); bw.Write((short)wavFormat.Channels); bw.Write(wavFormat.SampleRate); bw.Write((int)(wavFormat.SampleRate * ((wavFormat.BitsPerSample * wavFormat.Channels) / 8))); bw.Write((short)((wavFormat.BitsPerSample * wavFormat.Channels) / 8)); bw.Write((short)wavFormat.BitsPerSample); bw.Write(new char[4] { 'd', 'a', 't', 'a' }); bw.Write(length); bw.Write(audioData, startIndex, length); } finally { if (bw != null) { bw.Close(); } if (fs != null) { fs.Close(); fs.Dispose(); } } }
/// <summary> /// Update XMP Metadata usin Stream /// Feature is supported in version 18.6 or greater of the API /// </summary> public static void UpdateXmpMetadataUsingStream() { using (Stream stream = File.Open(Common.MapDestinationFilePath(filePath), FileMode.OpenOrCreate, FileAccess.ReadWrite)) { using (WavFormat format = new WavFormat(Common.MapSourceFilePath(filePath))) { Console.WriteLine(format.XmpValues.Schemes.XmpBasic.CreateDate); Console.WriteLine(format.XmpValues.Schemes.XmpBasic.Label); Console.WriteLine(format.XmpValues.Schemes.DublinCore.Subject); Console.WriteLine(format.XmpValues.Schemes.DublinCore.Format); format.XmpValues.Schemes.XmpBasic.CreateDate = DateTime.Now; format.XmpValues.Schemes.XmpBasic.Label = "Test"; format.XmpValues.Schemes.DublinCore.Subject = "WAV XMP Test"; format.XmpValues.Schemes.DublinCore.Format = "WAV Audio"; format.Save(stream); } // The stream is still open here } }
protected override void CreateInternal(ReadOnlyMemory <byte> data) { // Check if WAV. if (WavFormat.IsWav(data)) { // Get the data. ReadOnlySpan <byte> soundDataDecoded = WavFormat.Decode(data, out AudioFormat format).Span; if (format.SampleSize == 0) { Engine.Log.Error($"Error reading sound file {Name}.", MessageSource.Audio); return; } // Convert to float and store it as such. SoundData = new float[soundDataDecoded.Length / format.SampleSize]; for (var i = 0; i < SoundData.Length; i++) { SoundData[i] = AudioConverter.GetSampleAsFloat(i, soundDataDecoded, format); } OriginalFormat = format.Copy(); format.BitsPerSample = 32; format.IsFloat = true; ByteSize = SoundData.Length; Format = format; Duration = format.GetSoundDuration(SoundData.Length * sizeof(float)); AudioConverter = new AudioConverter(Format, SoundData, 10); if (Format.UnsupportedBitsPerSample()) { Engine.Log.Error($"The audio format of {Name} has an unsupported number of bits per sample ({Format.BitsPerSample}). Supported values are 8/16/32", MessageSource.Audio); } } if (Format == null || SoundData == null) { Engine.Log.Warning($"Couldn't load audio file - {Name}.", MessageSource.AssetLoader); } }
/// <summary> /// C# side of processing uploaded song from FilePicker when adding new song to the database. /// </summary> /// <param name="sender"></param> /// <param name="e">Instance with audio data and process status information.</param> private void OnNewSongUploadedEvent(object sender, string fileAsDataUrl, bool isDone) { //remove EventHandler in case this is the last iteration WasmSongEvent -= OnNewSongUploadedEvent; // Song is fully uploaded from javascript to C#, now convert uploaded data to Wav Format if (isDone) { // Convert audio data from Base64 string to byte array byte[] binData = Convert.FromBase64String(stringBuilder.ToString()); try { // Convert byte array to wav format songToBeAddedToDatabase = new WavFormat(binData); if (!IsSupported(songToBeAddedToDatabase)) { // Release resources songToBeAddedToDatabase = null; return; } } catch (ArgumentException ex) { this.Log().LogError(ex.Message); InformationText = "Problem with uploaded wav file occured." + Environment.NewLine + "Please try a different audio file."; return; } // Update UI UploadedSongText = fileAsDataUrl; InformationText = "File picked"; } else { stringBuilder.Append(fileAsDataUrl); // Repeat this event until e.isDone WasmSongEvent += OnNewSongUploadedEvent; } }
public void UnitWav_1() { var fName1 = @"Targets\Singles\StereoSilence10.wav"; WavFormat wav; using (Stream fs = new FileStream(fName1, FileMode.Open, FileAccess.Read)) { var hdr = new byte[0x2C]; var got = fs.Read(hdr, 0, hdr.Length); Assert.AreEqual(hdr.Length, got); WavFormat.Model wavModel = WavFormat.CreateModel(fs, hdr, fName1); wav = wavModel.Data; } Assert.AreEqual(Severity.NoIssue, wav.Issues.MaxSeverity); Assert.AreEqual(0, wav.Issues.Items.Count); Assert.AreEqual(2, wav.ChannelCount); Assert.AreEqual(44100u, wav.SampleRate); Assert.IsTrue(wav.HasTags); }
// Constructor for writing public SuperWAV(string path, WavFormat wavFormatForWritingA, UInt32 sampleRateA, UInt16 channelCountA, AudioFormat audioFormatA, UInt16 bitsPerSampleA, UInt64 initialDataLengthInTicks = 0) { openMode = OpenMode.CREATE_FOR_READ_WRITE; fs = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read); br = new BinaryReader(fs); bw = new BinaryWriter(fs); bytesPerSample = (UInt16)(bitsPerSampleA / 8); dataLengthInTicks = initialDataLengthInTicks; wavInfo.sampleRate = sampleRateA; wavInfo.channelCount = channelCountA; wavInfo.audioFormat = audioFormatA; wavInfo.bitsPerSample = bitsPerSampleA; wavInfo.bytesPerTick = (UInt16)(bytesPerSample * channelCountA); wavInfo.dataLength = initialDataLengthInTicks * wavInfo.bytesPerTick; wavInfo.byteRate = wavInfo.sampleRate * wavInfo.bytesPerTick; wavFormat = wavFormatForWritingA; writeFileHusk(wavFormatForWritingA, ref wavInfo); }
/// <summary> /// Creates concrete audio format from file. /// </summary> /// <param name="path">File Path.</param> /// <returns>Concrete implementation of IAudioFormat</returns> public static IAudioFormat GetAudio(string path) { byte[] data = File.ReadAllBytes(path); IAudioFormat Sound; // Currently only .wav files are supported. if (path.EndsWith(".wav")) { //Check if the beginning starts with RIFF (currently only supported format of wav files) if (!WavFormat.IsCorrectFormat(new[] { data[0], data[1], data[2], data[3] })) { throw new ArgumentException($"File {path} formatted wrongly, not a 'wav' format."); } Sound = new WavFormat(data); } else { throw new NotImplementedException($"Format of file {path} is not implemented."); } return(Sound); }
public AudioRecorder() { if (!EnsureAudioAccsess()) { throw new Exception("Accsess Denided: Cannot go on without a microphone..."); } Device = CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice(); var Devices = CaptureDeviceConfiguration.GetAvailableAudioCaptureDevices(); Device = Devices[0]; if (Device == null) { throw new Exception("Cannot go on without a microphone..."); } foreach (AudioFormat F in Device.SupportedFormats) { if (F.BitsPerSample == 16 && F.Channels == 1 && F.SamplesPerSecond == 44100) { Device.DesiredFormat = F; break; } } Format = new WavFormat(Device.DesiredFormat.SamplesPerSecond, Device.DesiredFormat.BitsPerSample, Device.DesiredFormat.Channels); Source = new CaptureSource { AudioCaptureDevice = Device }; CaptureSource = Source; SaveToStream = false; IgnoreFirstSample = true; }
// Write the bare minimum for a working file. private void writeFileHusk(WavFormat wavFormatA, ref WavInfo wavInfoA) { checkClosed(); if (openMode == OpenMode.CREATE_FOR_READ_WRITE) { if (wavFormatA == WavFormat.WAVE) { bw.Seek(0, SeekOrigin.Begin); bw.Write("RIFF".ToCharArray()); bw.Write((UInt32)0); bw.Write("WAVE".ToCharArray()); bw.Write("fmt ".ToCharArray()); bw.Write((UInt32)16); bw.Write((UInt16)wavInfoA.audioFormat); bw.Write((UInt16)wavInfoA.channelCount); bw.Write((UInt32)wavInfoA.sampleRate); bw.Write((UInt32)wavInfoA.byteRate); bw.Write((UInt16)wavInfoA.bytesPerTick); bw.Write((UInt16)wavInfoA.bitsPerSample); bw.Write("data".ToCharArray()); bw.Write((UInt32)wavInfoA.dataLength); wavInfoA.dataOffset = (UInt64)bw.BaseStream.Position; bw.BaseStream.Seek((Int64)wavInfoA.dataLength /*-1*/, SeekOrigin.Current); bw.Write((byte)0); Int64 currentPosition = bw.BaseStream.Position; bw.Seek(4, SeekOrigin.Begin); bw.Write((UInt32)currentPosition - 8); // TODO Check if -8 is actually correct } else if (wavFormat == WavFormat.WAVE64) { bw.Seek(0, SeekOrigin.Begin); bw.Write("riff".ToCharArray()); bw.Write(WAVE64_GUIDFOURCC_RIFF_LAST12); bw.Write((UInt64)0); bw.Write("wave".ToCharArray()); bw.Write(WAVE64_GUIDFOURCC_LAST12); bw.Write("fmt ".ToCharArray()); bw.Write(WAVE64_GUIDFOURCC_LAST12); bw.Write((UInt64)(16 + WAVE64_SIZE_DIFFERENCE)); bw.Write((UInt16)wavInfoA.audioFormat); bw.Write((UInt16)wavInfoA.channelCount); bw.Write((UInt32)wavInfoA.sampleRate); bw.Write((UInt32)wavInfoA.byteRate); bw.Write((UInt16)wavInfoA.bytesPerTick); bw.Write((UInt16)wavInfoA.bitsPerSample); bw.Write("data".ToCharArray()); bw.Write(WAVE64_GUIDFOURCC_LAST12); bw.Write((UInt64)wavInfoA.dataLength + WAVE64_SIZE_DIFFERENCE); wavInfoA.dataOffset = (UInt64)bw.BaseStream.Position; bw.BaseStream.Seek((Int64)wavInfoA.dataLength /*-1*/, SeekOrigin.Current); bw.Write((byte)0); Int64 currentPosition = bw.BaseStream.Position; bw.Seek(4 + 12, SeekOrigin.Begin); bw.Write((UInt64)currentPosition); } else if (wavFormat == WavFormat.RF64) { throw new Exception("Writing RF64 is not yet implemented."); } else { throw new Exception("Whut? " + wavFormat + "? What do you mean by " + wavFormat + "?"); } } else { throw new Exception("Trying to initialize an already existing file! Don't do that!"); } }
private void Import(BinaryReader reader, BinaryWriter writer) { // Read the header. WavHeader header = new WavHeader(); header.chunkId = reader.ReadUInt32(); header.chunkSize = reader.ReadUInt32(); header.format = reader.ReadUInt32(); // Ensure the file is a valid wav file if (header.chunkId != 0x46464952 || header.format != 0x45564157L) { throw new ImportException("not a valid .wav file"); } // Read the block type WavFormat format = new WavFormat(); uint dataSize = 0; long dataPosition = 0; // Read header blocks.. while (reader.BaseStream.Position != reader.BaseStream.Length) { var blockId = reader.ReadUInt32(); // Read the size of the block var blockSize = reader.ReadUInt32(); blockSize += ((blockSize & 1) != 0 ? 1U : 0U); // Next block position var next = reader.BaseStream.Position + blockSize; switch (blockId) { // FMT case 0x20746d66: { format.type = reader.ReadUInt16(); format.channels = reader.ReadUInt16(); format.samplesPerSec = reader.ReadUInt32(); format.avgBytesPerSec = reader.ReadUInt32(); format.blockAlign = reader.ReadUInt16(); format.bitsPerSample = reader.ReadUInt16(); break; } // DATA case 0x61746164: { dataSize = blockSize; dataPosition = reader.BaseStream.Position; break; } } // Skip to next block reader.BaseStream.Position = next; } if (dataSize == 0 || dataPosition == 0) { throw new ImportException("invalid or corrupt .wav file"); } // 8-bit format not allowed if (format.bitsPerSample != 16) { throw new ImportException("only 16-bit PCM data supported"); } var bytesPerSample = format.channels * (format.bitsPerSample >> 3); var sampleCount = (int)(dataSize / bytesPerSample); // Create the clip var clip = AudioClip.Create(sampleCount, format.channels == 1 ? AudioChannelFormat.Mono : AudioChannelFormat.Stereo, (int)format.samplesPerSec); // Read the data reader.BaseStream.Position = dataPosition; byte[] data = reader.ReadBytes((int)dataSize); short[] pcm = new short[(int)dataSize / 2]; Buffer.BlockCopy(data, 0, pcm, 0, (int)dataSize); clip.SetData(pcm, 0); clip.Save(writer); }
/// <summary> /// Reads audio details /// </summary> public static void ReadAudioDetails() { try { //ExStart:ReadAudioDetailsInWav // initialize WavFormat class WavFormat wavFormat = new WavFormat((Common.MapSourceFilePath(filePath))); // get audio info WavAudioInfo audioInfo = wavFormat.AudioInfo; // display bits per sample Console.WriteLine("Bits per sample: {0}", audioInfo.BitsPerSample); // display audio format version Console.WriteLine("Audio format: {0}", audioInfo.AudioFormat); // display number of channels Console.WriteLine("Number of channels: {0}", audioInfo.NumberOfChannels); // display sample rate Console.WriteLine("Sample rate: {0}", audioInfo.SampleRate); //ExEnd:ReadAudioDetailsInWav } catch (Exception ex) { Console.WriteLine(ex.Message); } }
private SampleInfo ParseHeader() { // If we are here, it means that the first part of the header // (the format) has already been checked _stream.Seek(12, SeekOrigin.Begin); int sampleCount = 0; short channelCount = 0; int sampleRate = 0; // Parse all the sub-chunks bool dataChunkFound = false; var reader = new BinaryReader(_stream); while (!dataChunkFound) { // Parse the sub-chunk id and size byte[] subChunkId = new byte[4]; if (_stream.Read(subChunkId, 0, 4) != 4) { throw new Exception("Failed to open WAV sound file (invalid or unsupported file)"); } int subChunkSize = reader.ReadInt32(); // Check which chunk it is var signature = Encoding.UTF8.GetString(subChunkId); if (signature == "fmt ") { // "fmt" chunk // Audio format short format = reader.ReadInt16(); _format = (WavFormat)format; //if (format != 1) // PCM //throw new Exception("Failed to open WAV sound file (invalid or unsupported file)"); // Channel count channelCount = reader.ReadInt16(); // Sample rate sampleRate = reader.ReadInt32(); // Byte rate int byteRate = reader.ReadInt32(); // Block align short blockAlign = reader.ReadInt16(); // Bits per sample short bitsPerSample = reader.ReadInt16(); if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 && bitsPerSample != 32) { throw new FormatException( "Unsupported sample size: " + bitsPerSample.ToString() + " bit (Supported sample sizes are 8/16/24/32 bit)" ); } _bytesPerSample = bitsPerSample / 8; // Skip potential extra information (should not exist for PCM) if (subChunkSize > 16) { if (_stream.Seek(subChunkSize - 16, SeekOrigin.Current) == -1) { throw new Exception("Failed to open WAV sound file (invalid or unsupported file)"); } } } else if (signature == "data") { // "data" chunk // Compute the total number of samples sampleCount = subChunkSize / _bytesPerSample; // Store the start and end position of samples in the file _offsetStart = _stream.Position; _offsetEnd = _offsetStart + sampleCount * _bytesPerSample; dataChunkFound = true; } else { // unknown chunk, skip it if (_stream.Seek(subChunkSize, SeekOrigin.Current) == -1) { throw new Exception("Failed to open WAV sound file (invalid or unsupported file)"); } } } return(new SampleInfo(sampleCount, channelCount, sampleRate)); }
private SampleInfo ParseHeader() { // If we are here, it means that the first part of the header // (the format) has already been checked _stream.Seek(12, SeekOrigin.Begin); int sampleCount = 0; short channelCount = 0; int sampleRate = 0; // Parse all the sub-chunks bool dataChunkFound = false; var reader = new BinaryReader(_stream); while (!dataChunkFound) { // Parse the sub-chunk id and size byte[] subChunkId = new byte[4]; if (_stream.Read(subChunkId, 0, 4) != 4) throw new Exception("Failed to open WAV sound file (invalid or unsupported file)"); int subChunkSize = reader.ReadInt32(); // Check which chunk it is var signature = Encoding.UTF8.GetString(subChunkId); if (signature == "fmt ") { // "fmt" chunk // Audio format short format = reader.ReadInt16(); _format = (WavFormat)format; //if (format != 1) // PCM //throw new Exception("Failed to open WAV sound file (invalid or unsupported file)"); // Channel count channelCount = reader.ReadInt16(); // Sample rate sampleRate = reader.ReadInt32(); // Byte rate int byteRate = reader.ReadInt32(); // Block align short blockAlign = reader.ReadInt16(); // Bits per sample short bitsPerSample = reader.ReadInt16(); if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 && bitsPerSample != 32) { throw new FormatException( "Unsupported sample size: " + bitsPerSample.ToString() + " bit (Supported sample sizes are 8/16/24/32 bit)" ); } _bytesPerSample = bitsPerSample / 8; // Skip potential extra information (should not exist for PCM) if (subChunkSize > 16) { if (_stream.Seek(subChunkSize - 16, SeekOrigin.Current) == -1) throw new Exception("Failed to open WAV sound file (invalid or unsupported file)"); } } else if (signature == "data") { // "data" chunk // Compute the total number of samples sampleCount = subChunkSize / _bytesPerSample; // Store the start and end position of samples in the file _offsetStart = _stream.Position; _offsetEnd = _offsetStart + sampleCount * _bytesPerSample; dataChunkFound = true; } else { // unknown chunk, skip it if (_stream.Seek(subChunkSize, SeekOrigin.Current) == -1) throw new Exception("Failed to open WAV sound file (invalid or unsupported file)"); } } return new SampleInfo(sampleCount, channelCount, sampleRate); }
/// <summary> /// C# side processing of uploaded or recorded audio data when recognizing song. /// </summary> /// <param name="sender"></param> /// <param name="e">Instance with audio data and process status information.</param> private async void OnSongToRecognizeEvent(object sender, string fileAsDataUrl, bool isDone) { //remove EventHandler in case this is the last iteration WasmSongEvent -= OnSongToRecognizeEvent; // Audio data is fully uploaded from javascript to C#, now recognize the song if (isDone) { // Update UI IsRecording = false; IsUploading = false; IsRecognizing = true; InformationText = "Looking for a match ..."; try { // Convert audio data from Base64 string to byteArray //string base64Data = Regex.Match(stringBuilder.ToString(), @"data:((audio)|(application))/(?<type>.+?),(?<data>.+)").Groups["data"].Value; byte[] binData = Convert.FromBase64String(stringBuilder.ToString()); //this is the data I want byte[] // Convert byte array to wav format uploadedSong = new WavFormat(binData); if (!IsSupported(uploadedSong)) { //release resources uploadedSong = null; return; } } // catch error that caused by faulty binData // ArgumentException at WavFormat(binData) // NullReferenceException at Regex.Match().Groups[]-Value catch (Exception ex) { this.Log().LogError(ex.Message); InformationText = "Error occured, please try again."; IsRecognizing = false; return; } //Debug print recorded audio properties this.Log().LogDebug("[DEBUG] Channels: " + uploadedSong.Channels); this.Log().LogDebug("[DEBUG] SampleRate: " + uploadedSong.SampleRate); this.Log().LogDebug("[DEBUG] NumOfData: " + uploadedSong.NumOfDataSamples); this.Log().LogDebug("[DEBUG] ActualNumOfData: " + uploadedSong.Data.Length); //Name, Author and Lyrics is not important for recognition call PreprocessedSongData songWavFormat = PreprocessSongData(uploadedSong); RecognitionResult result = await recognizerApi.RecognizeSong(songWavFormat); // Update UI await WriteRecognitionResults(result); IsRecognizing = false; } else { stringBuilder.Append(fileAsDataUrl); //repeat this event until e.isDone == true; WasmSongEvent += OnSongToRecognizeEvent; } }
/// <summary> /// Open a <see cref="Stream"/> of sound for reading. /// </summary> /// <param name="stream"><see cref="Stream"/> to open.</param> /// <param name="leaveOpen">Specifies whether the <paramref name="stream"/> should leave open after the current instance of the <see cref="SoundReader"/> disposed.</param> /// <returns>A <see cref="SampleInfo"/> containing sample information if decoder is can handle the stream, otherwise <c>null</c>.</returns> /// <inheritdoc/> protected internal override SampleInfo Initialize(Stream stream, bool leaveOpen = false) { // If we are here, it means that the first part of the header // (the format) has already been checked stream.Seek(12, SeekOrigin.Begin); using (var reader = new BinaryReader(stream, Encoding.UTF8, true)) { int sampleCount = 0; short channelCount = 0; int sampleRate = 0; // Parse all the sub-chunks bool dataChunkFound = false; while (!dataChunkFound) { // Parse the sub-chunk id byte[] subChunkId = new byte[4]; if (stream.Read(subChunkId, 0, 4) != 4) { throw new FormatException("Failed to open WAV sound file (invalid or unsupported file)"); } // Get chunk information int subChunkSize = reader.ReadInt32(); long subChunkStart = stream.Position; // Check whether the signature is valid, either fmt or data string signature = Encoding.UTF8.GetString(subChunkId); if (signature == "fmt ") { // Audio format format = (WavFormat)reader.ReadInt16(); if (format != WavFormat.PCM && format != WavFormat.Float) { throw new NotSupportedException("Wav format is not supported."); } // Channel count channelCount = reader.ReadInt16(); // Sample rate sampleRate = reader.ReadInt32(); // Byte rate int byteRate = reader.ReadInt32(); // Block align short blockAlign = reader.ReadInt16(); // Bits per sample short bitsPerSample = reader.ReadInt16(); if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 && bitsPerSample != 32) { throw new NotSupportedException( $"Unsupported sample size: {bitsPerSample} bit (Supported sample sizes are 8/16/24/32 bit)" ); } else { bytesPerSample = bitsPerSample / 8; } // Skip potential extra information (should not exist for PCM) if (subChunkSize > 16) { if (stream.Seek(subChunkSize - 16, SeekOrigin.Current) == -1) { throw new FormatException( "Failed to open WAV sound file (invalid or unsupported file)"); } } } else if (signature == "data") { // Compute the total number of samples sampleCount = subChunkSize / bytesPerSample; // Store the start and end position of samples in the file dataStart = subChunkStart; dataEnd = dataStart + sampleCount * bytesPerSample; dataChunkFound = true; } else { // unknown chunk, skip it if (stream.Seek(subChunkSize, SeekOrigin.Current) == -1) { throw new FormatException( "Failed to open WAV sound file (invalid or unsupported file)"); } } } return(new SampleInfo(sampleCount, channelCount, sampleRate)); } }