public WaveOutBuffer(IntPtr waveOutHandle, int bufferSize, IntPtr userData) { if (waveOutHandle == IntPtr.Zero) { throw new ArgumentNullException("waveOutHandle"); } if (bufferSize <= 0) { throw new ArgumentOutOfRangeException("bufferSize"); } _waveOutHandle = waveOutHandle; _buffer = new byte[bufferSize]; _bufferHandle = GCHandle.Alloc(_buffer, GCHandleType.Pinned); _waveHeader = new WaveHeader() { bufferLength = bufferSize, dataBuffer = _bufferHandle.AddrOfPinnedObject(), loops = 1, userData = userData }; _waveHeaderHandle = GCHandle.Alloc(_waveHeaderHandle, GCHandleType.Pinned); //do we really need the waveheaderhandle? }
public SoundGenerator(List <SoundFragment> sound) { header = new WaveHeader(); format = new WaveFormatChunk(); data = new WaveDataChunk(); int numberOfSamples = sound.Sum(x => (int)(format.dwSamplesPerSec * format.wChannels * x.Duration)); data.shortArray = new short[numberOfSamples]; int amplitude = 32760; int counter = 0; foreach (SoundFragment fragment in sound) { double t = (Math.PI * 2 * fragment.Frequency) / (format.dwSamplesPerSec * format.wChannels); uint sampleCountForFragment = (uint)(format.dwSamplesPerSec * format.wChannels * fragment.Duration); for (uint i = 0; i < sampleCountForFragment - 1; i++) { for (int channel = 0; channel < format.wChannels; channel++) { data.shortArray[counter + channel] = Convert.ToInt16(amplitude * Math.Sin(t * i)); } counter++; } } data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8)); }
public unsafe static void Save(Song song, string filename, int sampleRate, int loopCount, int duration, int channelMask) { var project = song.Project; var player = new WavPlayer(sampleRate, loopCount, channelMask); var samples = player.GetSongSamples(song, project.PalMode, duration); using (var file = new FileStream(filename, FileMode.Create)) { var header = new WaveHeader(); // RIFF WAVE Header header.chunkId[0] = (byte)'R'; header.chunkId[1] = (byte)'I'; header.chunkId[2] = (byte)'F'; header.chunkId[3] = (byte)'F'; header.format[0] = (byte)'W'; header.format[1] = (byte)'A'; header.format[2] = (byte)'V'; header.format[3] = (byte)'E'; // Format subchunk header.subChunk1Id[0] = (byte)'f'; header.subChunk1Id[1] = (byte)'m'; header.subChunk1Id[2] = (byte)'t'; header.subChunk1Id[3] = (byte)' '; header.audioFormat = 1; // FOR PCM header.numChannels = 1; // 1 for MONO, 2 for stereo header.sampleRate = sampleRate; // ie 44100 hertz, cd quality audio header.bitsPerSample = 16; // header.byteRate = header.sampleRate * header.numChannels * header.bitsPerSample / 8; header.blockAlign = (short)(header.numChannels * header.bitsPerSample / 8); // Data subchunk header.subChunk2Id[0] = (byte)'d'; header.subChunk2Id[1] = (byte)'a'; header.subChunk2Id[2] = (byte)'t'; header.subChunk2Id[3] = (byte)'a'; // All sizes for later: // chuckSize = 4 + (8 + subChunk1Size) + (8 + subChubk2Size) // subChunk1Size is constanst, i'm using 16 and staying with PCM // subChunk2Size = nSamples * nChannels * bitsPerSample/8 // Whenever a sample is added: // chunkSize += (nChannels * bitsPerSample/8) // subChunk2Size += (nChannels * bitsPerSample/8) header.subChunk1Size = 16; header.subChunk2Size = samples.Length * sizeof(short); header.chunkSize = 4 + (8 + header.subChunk1Size) + (8 + header.subChunk2Size); var headerBytes = new byte[sizeof(WaveHeader)]; Marshal.Copy(new IntPtr(&header), headerBytes, 0, headerBytes.Length); file.Write(headerBytes, 0, headerBytes.Length); // So lame. foreach (var s in samples) { file.Write(BitConverter.GetBytes(s), 0, sizeof(short)); } } }
public WaveGenerator(List <Note> notes, float volume) { // Init chunks header = new WaveHeader(); format = new WaveFormatChunk(); data = new WaveDataChunk(); var milliseconds = notes.Select((x) => x.Duration.TotalMilliseconds).Sum(); uint numSamples = (uint)(((format.dwSamplesPerSec * milliseconds) / 1000)); int amplitude = 32760; // Max amplitude for 16-bit audio uint sampleCount = 0; // used as a "cursor" in the next Foreach // Initialize the 16-bit array and Calculate the repsective values data.shortArray = new short[numSamples]; foreach (var n in notes) { // the time-steps the sine wave takes (period [2 pi f]) divided by the steps per period double t = (Math.PI * 2 * n.Frequency) / format.dwSamplesPerSec; // Calculate the amount of samples you will use for said Note var samplesThisNote = format.dwSamplesPerSec * n.Duration.TotalSeconds; // Loop over sampleCount as said before (it acts as u cursor) for (uint i = sampleCount; i < (samplesThisNote + sampleCount) - 1; i++) { data.shortArray[i] = Convert.ToInt16(amplitude * Math.Sin(t * i) * volume); } sampleCount += (uint)samplesThisNote; } // Calculate data chunk size in bytes data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8)); }
/// <summary> /// Called when we get a new buffer of recorded data /// </summary> private void Callback(IntPtr waveInHandle, WaveInterop.WaveMessage message, IntPtr userData, WaveHeader waveHeader, IntPtr reserved) { if (message == WaveInterop.WaveMessage.WaveInData) { if (recording) { var hBuffer = (GCHandle)waveHeader.userData; var buffer = (WaveInBuffer)hBuffer.Target; if (buffer == null) { return; } lastReturnedBufferIndex = Array.IndexOf(buffers, buffer); RaiseDataAvailable(buffer); try { buffer.Reuse(); } catch (Exception e) { recording = false; RaiseRecordingStopped(e); } } } }
double freq = 220.0f; // Concert A: 440Hz public WaveGenerator() { // Init chunks header = new WaveHeader(); format = new WaveFormatChunk(); data = new WaveDataChunk(); }
public void StopRecord() { RecordData recordData = StopRec(); bData = new byte[recordData.len]; Debug.WriteLine(recordData.len); Marshal.Copy(recordData.ip, bData, 0, (int)recordData.len); WaveHeader header = (WaveHeader)Marshal.PtrToStructure(GetWaveform(), typeof(WaveHeader)); wav = new Wav("RIFF", recordData.len + 36, "WAVE", "fmt", 16, 1, header.nChannels, header.nSamplesPerSec, header.nAvgBytesPerSec, header.nBlockAlign, header.wBitsPerSample, "data", recordData.len); short[] temp = new short[recordData.len / (int)wav.blockAlign]; for (int i = 0; i < temp.Length - 1; i++) { temp[i] = BitConverter.ToInt16(bData, i * (int)wav.blockAlign); } samples = temp.Select(x => (double)(x)).ToArray(); plotSample(samples.Length); }
public void SaveAsWaveFile(string fileName, IEnumerable <SpeechPart> audioData) { int dataLength = 0; foreach (SpeechPart item in audioData) { dataLength += item.RawAudio.Length; } byte[] headerByte = new WaveHeader( 1, //单声道 16000, //采样频率 16, //每个采样8bit dataLength).ToBytes(); using (FileStream stream = File.Create(fileName)) { //写入文件头 stream.Write(headerByte, 0, headerByte.Length); foreach (SpeechPart item in audioData) { stream.Write(item.RawAudio, 0, item.RawAudio.Length); } stream.Flush(); stream.Close(); } }
public static void PlayTone(Tone[] tones) { WAVEFORMAT_MIDI wfm = new WAVEFORMAT_MIDI(); wfm.WAVEFORMATEX.FormatTag = FormatTag.MIDI; wfm.WAVEFORMATEX.Channels = 1; wfm.WAVEFORMATEX.BlockAlign = 8; // sizeof(WAVEFORMAT_MIDI_MESSAGE); wfm.WAVEFORMATEX.Size = WAVEFORMAT_MIDI_EXTRASIZE; // trial & error seems to be the way to get this - tested using an Axim x51 // maybe expose these if it varies from hardware to hardware wfm.USecPerQuarterNote = 100000; wfm.TicksPerQuarterNote = 15; IntPtr hWaveOut; EventWaitHandle hEvent = new EventWaitHandle(false, EventResetMode.ManualReset); byte[] d = wfm.GetBytes(); int result = WaveAudio.NativeMethods.waveOutOpen(out hWaveOut, 0, d, hEvent.Handle, 0, CALLBACK_EVENT); Audio.CheckWaveError(result); WAVEFORMAT_MIDI_MESSAGE[] messages = new WAVEFORMAT_MIDI_MESSAGE[2 * tones.Length]; int totalDuration = 0; for (int i = 0; i < tones.Length; i++) { messages[i * 2].DeltaTicks = 0; messages[i * 2].MidiMsg = (uint)(0x7F0090 | (tones[i].MIDINote << 8)); // Note on messages[i * 2 + 1].DeltaTicks = (uint)(tones[i].Duration); messages[i * 2 + 1].MidiMsg = (uint)(0x7F0080 | (tones[i].MIDINote << 8)); // Note off totalDuration += tones[i].Duration; } byte[] headerData = new byte[messages.Length * WAVEFORMAT_MIDI_MESSAGE.Length]; for (int i = 0; i < messages.Length; i++) { Buffer.BlockCopy(messages[i].GetBytes(), 0, headerData, i * WAVEFORMAT_MIDI_MESSAGE.Length, WAVEFORMAT_MIDI_MESSAGE.Length); } WaveHeader header = new WaveHeader(headerData); result = WaveAudio.NativeMethods.waveOutPrepareHeader(hWaveOut, header.Pointer, header.HeaderLength); Audio.CheckWaveError(result); result = WaveAudio.NativeMethods.waveOutWrite(hWaveOut, header.Pointer, header.HeaderLength); Audio.CheckWaveError(result); if (!hEvent.WaitOne(totalDuration * 20, false)) { Debugger.Break(); } result = WaveAudio.NativeMethods.waveOutUnprepareHeader(hWaveOut, header.Pointer, header.HeaderLength); Audio.CheckWaveError(result); result = WaveAudio.NativeMethods.waveOutClose(hWaveOut); Audio.CheckWaveError(result); }
protected virtual void Dispose(bool disposing) { if (disposing) { //dispose managed } if (_header != null) { try { Unprepare(); } catch (Exception) { } finally { _header = null; } } if (_bufferHandle.IsAllocated) { _bufferHandle.Free(); } if (_headerHandle.IsAllocated) { _headerHandle.Free(); } if (_userDataHandle.IsAllocated) { _userDataHandle.Free(); } }
public fileSaver(WaveHeader header, WaveFormatChunk format, WaveDataChunk data, string filePath) { using (var fileStream = new FileStream(filePath, FileMode.Create)) { using (var writer = new BinaryWriter(fileStream)) { // Write the header writer.Write(header.sGroupID.ToCharArray()); writer.Write(header.dwFileLength); writer.Write(header.sRiffType.ToCharArray()); // Write the format chunk writer.Write(format.sChunkID.ToCharArray()); writer.Write(format.dwChunkSize); writer.Write(format.wFormatTag); writer.Write(format.wChannels); writer.Write(format.dwSamplesPerSec); writer.Write(format.dwAvgBytesPerSec); writer.Write(format.wBlockAlign); writer.Write(format.wBitsPerSample); // Write the data chunk writer.Write(data.sChunkID.ToCharArray()); writer.Write(data.dwChunkSize); foreach (short dataPoint in data.shortArray) { writer.Write(dataPoint); } // Jump back to Header.FileLength and calculate the TOTAL filesize writer.Seek(4, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length - 8); // Header parts are ignore (-8) } } }
protected override void WndProc(ref Message m) { var message = (WaveInterop.WaveMessage)m.Msg; switch (message) { case WaveInterop.WaveMessage.WaveOutDone: case WaveInterop.WaveMessage.WaveInData: var hOutputDevice = m.WParam; var waveHeader = new WaveHeader(); Marshal.PtrToStructure(m.LParam, waveHeader); _waveCallback(hOutputDevice, message, IntPtr.Zero, waveHeader, IntPtr.Zero); break; case WaveInterop.WaveMessage.WaveOutOpen: case WaveInterop.WaveMessage.WaveOutClose: case WaveInterop.WaveMessage.WaveInClose: case WaveInterop.WaveMessage.WaveInOpen: _waveCallback(m.WParam, message, IntPtr.Zero, null, IntPtr.Zero); break; default: base.WndProc(ref m); break; } }
public void Write (float[] clipData, WaveFormatChunk format, FileStream stream) { WaveHeader header = new WaveHeader (); WaveDataChunk data = new WaveDataChunk (); data.shortArray = new short[clipData.Length]; for (int i = 0; i < clipData.Length; i++) data.shortArray [i] = (short)(clipData [i] * 32767); data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8)); BinaryWriter writer = new BinaryWriter (stream); writer.Write (header.sGroupID.ToCharArray ()); writer.Write (header.dwFileLength); writer.Write (header.sRiffType.ToCharArray ()); writer.Write (format.sChunkID.ToCharArray ()); writer.Write (format.dwChunkSize); writer.Write (format.wFormatTag); writer.Write (format.wChannels); writer.Write (format.dwSamplesPerSec); writer.Write (format.dwAvgBytesPerSec); writer.Write (format.wBlockAlign); writer.Write (format.wBitsPerSample); writer.Write (data.sChunkID.ToCharArray ()); writer.Write (data.dwChunkSize); foreach (short dataPoint in data.shortArray) { writer.Write (dataPoint); } writer.Seek (4, SeekOrigin.Begin); uint filesize = (uint)writer.BaseStream.Length; writer.Write (filesize - 8); writer.Close (); }
public static WaveHeader ReadWaveHeader(Stream stream) { if (stream == null) { return((WaveHeader)null); } using (BinaryReader reader = new BinaryReader(stream)) return(WaveHeader.ReadWaveHeader(reader)); }
public void BeginRecording() { waveHeader = new WaveHeader(); formatChunk = new FormatChunk(SampleRate, NumChannels); dataChunk = new DataChunk(); waveHeader.FileLength += formatChunk.Length(); IsRecording = true; onScreenDisplayHandler.EnqueueMessage("Sound recording started."); }
public static WaveHeader ReadWaveHeader(BinaryReader reader) { WaveHeader waveHeader = new WaveHeader(); waveHeader.RIFF = Encoding.ASCII.GetString(reader.ReadBytes(4)); waveHeader.Size = reader.ReadInt32(); waveHeader.WAVE = Encoding.ASCII.GetString(reader.ReadBytes(4)); if (waveHeader.RIFF.ToUpper() != "RIFF" || waveHeader.WAVE.ToUpper() != "WAVE") { return((WaveHeader)null); } while (waveHeader.FMT == null || waveHeader.FMT.ToLower() != "fmt") { waveHeader.FMT = Encoding.ASCII.GetString(reader.ReadBytes(4)); if (!(waveHeader.FMT.ToLower().Trim() == "fmt")) { uint num = reader.ReadUInt32(); reader.BaseStream.Seek((long)num, SeekOrigin.Current); } else { break; } } waveHeader.FmtChunkSize = reader.ReadInt32(); waveHeader.FormatId = reader.ReadInt16(); waveHeader.Channels = reader.ReadInt16(); waveHeader.Frequency = reader.ReadInt32(); waveHeader.DataSpeed = reader.ReadInt32(); waveHeader.BlockSize = reader.ReadInt16(); waveHeader.BitPerSample = reader.ReadInt16(); reader.BaseStream.Seek((long)(waveHeader.FmtChunkSize - 16), SeekOrigin.Current); while (waveHeader.DATA == null || waveHeader.DATA.ToLower() != "data") { waveHeader.DATA = Encoding.ASCII.GetString(reader.ReadBytes(4)); if (!(waveHeader.DATA.ToLower() == "data")) { uint num = reader.ReadUInt32(); reader.BaseStream.Seek((long)num, SeekOrigin.Current); } else { break; } } waveHeader.TrueWavBufSize = reader.ReadInt32(); waveHeader.TrueSamples = waveHeader.TrueWavBufSize / ((int)waveHeader.BitPerSample / 8) / (int)waveHeader.Channels; waveHeader.TrueWavBufIndex = (int)reader.BaseStream.Position; reader.BaseStream.Seek(0L, SeekOrigin.Begin); return(waveHeader); }
public void Initialize() { _buffer = new byte[_bufferSize]; _header = new WaveHeader(); _headerHandle = GCHandle.Alloc(_header, GCHandleType.Pinned); _bufferHandle = GCHandle.Alloc(_buffer, GCHandleType.Pinned); _userDataHandle = GCHandle.Alloc(this); _header.bufferLength = _bufferSize; _header.dataBuffer = _bufferHandle.AddrOfPinnedObject(); _header.loops = 1; _header.userData = (IntPtr)_userDataHandle; Prepare(); AddBuffer(); }
/// <summary> /// Initializes a new instance of the <see cref="DialogAudioOutputStream"/> class. /// </summary> /// <param name="format"> The audio format of the underlying data. </param> protected DialogAudioOutputStream(DialogAudio format) : this() { Contract.Requires(format != null); Contract.Requires(this.bufferStream.Position == 0); this.Format = format; var encoding = this.Format.Encoding; // For PCM streams, we will assume that there's no header information available and write what's needed // for playback. if (encoding.Subtype == "WAV" || encoding.Subtype == "PCM") { WaveHeader.WriteWaveFormatHeaderToStream(this.bufferStream, encoding, WaveHeaderLengthOption.UseMaximumLength); this.bufferStream.Seek(0, SeekOrigin.Begin); } }
/// <summary> /// creates a new wavebuffer /// </summary> /// <param name="waveInHandle">WaveIn device to write to</param> /// <param name="bufferSize">Buffer size in bytes</param> public WaveInBuffer(IntPtr waveInHandle, Int32 bufferSize) { this.bufferSize = bufferSize; buffer = new byte[bufferSize]; hBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); this.waveInHandle = waveInHandle; header = new WaveHeader(); hHeader = GCHandle.Alloc(header); header.dataBuffer = hBuffer.AddrOfPinnedObject(); header.bufferLength = bufferSize; header.loops = 1; hThis = GCHandle.Alloc(this); header.userData = (IntPtr)hThis; MmException.Try(WaveInterop.waveInPrepareHeader(waveInHandle, header, Marshal.SizeOf(header)), "waveInPrepareHeader"); MmException.Try(WaveInterop.waveInAddBuffer(waveInHandle, header, Marshal.SizeOf(header)), "waveInAddBuffer"); }
protected virtual void Callback(IntPtr handle, WaveMsg msg, UIntPtr user, WaveHeader header, UIntPtr reserved) { if (_hWaveOut != handle) { return; //message does not belong to this waveout instance } if (msg == WaveMsg.WOM_DONE) { GCHandle hBuffer = (GCHandle)header.userData; WaveOutBuffer buffer = hBuffer.Target as WaveOutBuffer; System.Threading.Interlocked.Decrement(ref _activeBuffers); if (buffer == null) { return; } if (_playbackState != SoundOut.PlaybackState.Stopped) { lock (_lockObj) { if (buffer.WriteData()) { System.Threading.Interlocked.Increment(ref _activeBuffers); } } } if (_activeBuffers == 0) { _playbackState = SoundOut.PlaybackState.Stopped; RaiseStopped(); } } else if (msg == WaveMsg.WOM_CLOSE) { var state = _playbackState; _playbackState = SoundOut.PlaybackState.Stopped; if (state != SoundOut.PlaybackState.Stopped) { RaiseStopped(); } Debug.WriteLine("WaveOut::Callback: Closing WaveOut."); } }
WaveHeader GetWaveHeader(int dataLen) { WaveHeader header = new WaveHeader() { riffID=0x46464952, fileSize=dataLen+36, riffType=0x45564157, fmtID=0x20746D66, fmtSize=16, fmtTag=0x0001, fmtChannel=1, fmtSamplesPerSec=16000, avgBytesPerSec=32000, blockAlign=2, BitsPerSameple=16, dataID=0x61746164, dataSize=dataLen }; return header; }
private GCHandle _hThis; // for the user callback /// <summary> /// creates a new wavebuffer /// </summary> /// <param name="hWaveOut">WaveOut device to write to</param> /// <param name="bufferSize">Buffer size in bytes</param> /// <param name="bufferFillStream">Stream to provide more data</param> /// <param name="waveOutLock">Lock to protect WaveOut API's from being called on >1 thread</param> public WaveOutBuffer(IntPtr hWaveOut, int bufferSize, IWaveProvider bufferFillStream, object waveOutLock) { BufferSize = bufferSize; _buffer = new byte[bufferSize]; _hBuffer = GCHandle.Alloc(_buffer, GCHandleType.Pinned); _hWaveOut = hWaveOut; _waveStream = bufferFillStream; _waveOutLock = waveOutLock; _header = new WaveHeader(); _hHeader = GCHandle.Alloc(_header, GCHandleType.Pinned); _header.dataBuffer = _hBuffer.AddrOfPinnedObject(); _header.bufferLength = bufferSize; _header.loops = 1; _hThis = GCHandle.Alloc(this); _header.userData = (IntPtr)_hThis; lock (waveOutLock) { MmException.Try(WaveInterop.waveOutPrepareHeader(hWaveOut, _header, Marshal.SizeOf(_header)), "waveOutPrepareHeader"); } }
/// <summary> /// creates a new wavebuffer /// </summary> /// <param name="hWaveOut">WaveOut device to write to</param> /// <param name="bufferSize">Buffer size in bytes</param> /// <param name="bufferFillStream">Stream to provide more data</param> /// <param name="waveOutLock">Lock to protect WaveOut API's from being called on >1 thread</param> public WaveOutBuffer(IntPtr hWaveOut, Int32 bufferSize, IWaveProvider bufferFillStream, object waveOutLock) { this.bufferSize = bufferSize; buffer = new byte[bufferSize]; hBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); this.hWaveOut = hWaveOut; waveStream = bufferFillStream; this.waveOutLock = waveOutLock; header = new WaveHeader(); hHeader = GCHandle.Alloc(header); header.dataBuffer = hBuffer.AddrOfPinnedObject(); header.bufferLength = bufferSize; header.loops = 1; hThis = GCHandle.Alloc(this); header.userData = (IntPtr)hThis; lock (waveOutLock) { MmException.Try(WaveInterop.waveOutPrepareHeader(hWaveOut, header, Marshal.SizeOf(header)), "waveOutPrepareHeader"); } }
public WaveGenerator(WaveExampleType type) { // Init chunks header = new WaveHeader(); format = new WaveFormatChunk(); data = new WaveDataChunk(); // Fill the data array with sample data switch (type) { case WaveExampleType.ExampleSineWave: // Number of samples = sample rate * channels * bytes per sample uint numSamples = format.dwSamplesPerSec * format.wChannels; // Initialize the 16-bit array data.shortArray = new short[numSamples]; int amplitude = 32760; // Max amplitude for 16-bit audio double freq = 440.0f; // Concert A: 440Hz // The "angle" used in the function, adjusted for the number of channels and sample rate. // This value is like the period of the wave. double t = (Math.PI * 2 * freq) / (format.dwSamplesPerSec * format.wChannels); for (uint i = 0; i < numSamples - 1; i++) { // Fill with a simple sine wave at max amplitude for (int channel = 0; channel < format.wChannels; channel++) { data.shortArray[i + channel] = Convert.ToInt16(amplitude * Math.Sin(t * i)); } } // Calculate data chunk size in bytes data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8)); break; } }
/// <summary> /// 根据数据段的长度,生产文件头 /// </summary> /// <param name="dataLen">音频数据长度</param> /// <returns>返回wav文件头结构体</returns> WaveHeader getWave_Header(int dataLen) { var wavHeader = new WaveHeader(); wavHeader.RiffID = 0x46464952; //字符RIFF wavHeader.FileSize = dataLen + 36; wavHeader.RiffType = 0x45564157; //字符WAVE wavHeader.FmtID = 0x20746D66; //字符fmt wavHeader.FmtSize = 16; wavHeader.FmtTag = 0x0001; wavHeader.FmtChannel = 1; //单声道 wavHeader.FmtSamplesPerSec = 16000; //采样频率 wavHeader.AvgBytesPerSec = 32000; //每秒所需字节数 wavHeader.BlockAlign = 2; //每个采样1个字节 wavHeader.BitsPerSample = 16; //每个采样8bit wavHeader.DataID = 0x61746164; //字符data wavHeader.DataSize = dataLen; return(wavHeader); }
public void Write(float[] clipData, WaveFormatChunk format, FileStream stream) { WaveHeader header = new WaveHeader(); WaveDataChunk data = new WaveDataChunk(); data.shortArray = new short[clipData.Length]; for (int i = 0; i < clipData.Length; i++) { data.shortArray [i] = (short)(clipData [i] * 32767); } data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8)); BinaryWriter writer = new BinaryWriter(stream); writer.Write(header.sGroupID.ToCharArray()); writer.Write(header.dwFileLength); writer.Write(header.sRiffType.ToCharArray()); writer.Write(format.sChunkID.ToCharArray()); writer.Write(format.dwChunkSize); writer.Write(format.wFormatTag); writer.Write(format.wChannels); writer.Write(format.dwSamplesPerSec); writer.Write(format.dwAvgBytesPerSec); writer.Write(format.wBlockAlign); writer.Write(format.wBitsPerSample); writer.Write(data.sChunkID.ToCharArray()); writer.Write(data.dwChunkSize); foreach (short dataPoint in data.shortArray) { writer.Write(dataPoint); } writer.Seek(4, SeekOrigin.Begin); uint filesize = (uint)writer.BaseStream.Length; writer.Write(filesize - 8); writer.Close(); }
public static AudioClip Load( string path, long SongLength, uAudio.uAudio_backend.uAudio uAudio, ref string szErrorMs) { string extension = Path.GetExtension(path); if (extension == ".wav" || extension == ".WAV") { WaveHeader waveHeader = WaveHeader.ReadWaveHeader(path); float[] rangedRawData = ExternalAudioClip.CreateRangedRawData(path, waveHeader.TrueWavBufIndex, waveHeader.TrueSamples, (int)waveHeader.Channels, (int)waveHeader.BitPerSample); return(rangedRawData.Length == 0 ? (AudioClip)null : ExternalAudioClip.CreateClip(Path.GetFileNameWithoutExtension(path), rangedRawData, waveHeader.TrueSamples, (int)waveHeader.Channels, waveHeader.Frequency)); } if (!(extension == ".mp3") && !(extension == ".MP3")) { return((AudioClip)null); } mp3AudioClip._uAudio = uAudio; AudioClip audioClip = mp3AudioClip.LoadMp3(path, SongLength); szErrorMs = mp3AudioClip.szErrorMs; return(audioClip); }
public WaveGenerator(List <short> Data) { header = new WaveHeader(); format = new WaveFormatChunk(); data = new WaveDataChunk(); int numSamples = Data.Count; data.shortArray = new short[numSamples]; for (int i = 0; i < numSamples; i++) { data.shortArray[i] = Data[i]; } data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8)); TimeSpan TS = new TimeSpan(0, 0, (int)((float)numSamples / (float)format.dwSamplesPerSec)); if (Verbose) { Console.WriteLine(""); } Console.WriteLine("wave generated: {0} seconds: {1}", (float)numSamples / (float)format.dwSamplesPerSec, TS.ToString()); }
protected virtual void Callback(IntPtr handle, WaveMsg msg, UIntPtr user, WaveHeader header, UIntPtr reserved) { if (msg == WaveMsg.WIM_DATA) { if (!stopped) { var buffer = ((GCHandle)header.userData).Target as WaveInBuffer; RaiseDataAvailable(buffer); try { buffer.Reset(); } catch (MmException) { stopped = true; RaiseStopped(); } } } else if (msg == WaveMsg.WIM_CLOSE) { RaiseStopped(); } }
/// <summary> /// Main program. /// </summary> /// <param name="args"></param> private void Run(string[] args) { if (args.Length == 0) { Console.WriteLine( @"{0} [options ...] <path to MIDI.mid> Description: Clicker generates a WAVE file click track given a MIDI sequence with meter/key and tempo change messages. The click track serves as a solid, sample-accurate metronome that will line up with the MIDI sequence. You can import the generated click track into any MIDI-friendly DAW tool such as SONAR, Cubase, etc. to record with. You can even share the click track with other recording artists working on your project to serve as a timebase to help synchronize work across distances. Author: James S. Dunne http://bittwiddlers.org/ Copyright: 2011, bittwiddlers.org Source: http://github.com/JamesDunne/clicker Options: -s <samplerate> Set the output WAVE file's sample rate in Hz (default 48000 Hz) -c <channels> Set the output WAVE file's number of channels (1 or 2, default 2) -d <click division> Set the metronome to click on each (2^N)th note, scaling meter signatures appropriately to match. (default: off, click on meter beats only) -ao Attenuate meter's off-beats if meter is faster than the metronome. (default: off) -ad Attenuate inserted beats if metronome is clicking faster than the meter. (default: off) <path to MIDI.mid> Path to the MIDI arrangement to generate the click track for. Outputs: <path to MIDI.mid>.click.wav ", Process.GetCurrentProcess().ProcessName); return; } bool early = false; Queue<string> aq = new Queue<string>(args); while (!early && (aq.Count > 0)) { string arg = aq.Peek(); switch (arg.ToLower()) { case "-s": aq.Dequeue(); if (!Int32.TryParse(aq.Dequeue(), out samplesPerSec)) samplesPerSec = 48000; break; case "-c": aq.Dequeue(); if (!Int32.TryParse(aq.Dequeue(), out channels)) channels = 1; break; case "-d": aq.Dequeue(); if (Int32.TryParse(aq.Dequeue(), out clickOnDivision)) forceClickDivision = true; break; case "-ao": aq.Dequeue(); attenuateProperOffBeats = true; break; case "-ad": aq.Dequeue(); attenuateDividedBeats = true; break; default: early = true; break; } } if (aq.Count < 1) { Console.WriteLine("Expected path to MIDI sequence."); return; } FileInfo midiFile = new FileInfo(aq.Dequeue()); if (!midiFile.Exists) { Console.WriteLine("Could not find path '{0}'.", midiFile.FullName); return; } // Load the MIDI sequence: Sequence seq = new Sequence(midiFile.FullName); // Load our clicks (stereo 16-bit clips): var asm = System.Reflection.Assembly.GetExecutingAssembly(); #if true byte[] pinghiraw = getAllBytes(asm.GetManifestResourceStream("Clicker.pinghi48k16b.raw")); #else byte[] pinghiraw = File.ReadAllBytes("pinghi48k16b.raw"); #endif short[,] pinghi = new short[pinghiraw.Length / 4, 2]; for (int i = 0, b = 0; i < pinghiraw.Length - 4; i += 4, ++b) { pinghi[b, 0] = unchecked((short)(pinghiraw[i + 0] | (pinghiraw[i + 1] << 8))); pinghi[b, 1] = unchecked((short)(pinghiraw[i + 2] | (pinghiraw[i + 3] << 8))); } int pinghiLength = pinghi.GetUpperBound(0) + 1; #if true byte[] pingloraw = getAllBytes(asm.GetManifestResourceStream("Clicker.pinglo48k16b.raw")); #else byte[] pingloraw = File.ReadAllBytes("pinglo48k16b.raw"); #endif short[,] pinglo = new short[pingloraw.Length / 4, 2]; for (int i = 0, b = 0; i < pingloraw.Length - 4; i += 4, ++b) { pinglo[b, 0] = unchecked((short)(pingloraw[i + 0] | (pingloraw[i + 1] << 8))); pinglo[b, 1] = unchecked((short)(pingloraw[i + 2] | (pingloraw[i + 3] << 8))); } int pingloLength = pinglo.GetUpperBound(0) + 1; // Grab meter and tempo changes from any track: var timeChanges = from tr in seq from ev in tr.Iterator() where ev.MidiMessage.MessageType == MessageType.Meta let mm = (MetaMessage)ev.MidiMessage where mm.MetaType == MetaType.TimeSignature || mm.MetaType == MetaType.Tempo orderby ev.AbsoluteTicks ascending select new { ev, mm }; var lastEvent = ( from tr in seq from ev in tr.Iterator() orderby ev.AbsoluteTicks ascending select ev ).Last(); // Create a default tempo of 120 bpm (500,000 us/b): var tcb = new TempoChangeBuilder() { Tempo = 500000 }; tcb.Build(); currentTempo = new TempoMessage(tcb.Result); // Create a default time signature of 4/4: var tsb = new TimeSignatureBuilder() { Numerator = 4, Denominator = 4 }; tsb.Build(); currentTimeSignature = new TimeSignatureMessage(tsb.Result); ticksPerQuarter = seq.Division; calcUsecPerTick(); calcBeatTicks(); double sample = 0d; samplesPerUsec = (double)samplesPerSec / 1000000d; string outWaveFile = Path.Combine(midiFile.Directory.FullName, midiFile.Name + ".click.wav"); Console.WriteLine("Writing click track to '{0}'", outWaveFile); var format = new WaveFormatChunk(); format.dwSamplesPerSec = (uint)samplesPerSec; format.wChannels = (ushort)channels; format.wBitsPerSample = (ushort)bitsPerSample; Console.WriteLine( "Sample rate = {0,6} Hz; Channels = {1,1}; BitsPerSample = {2,2}", format.dwSamplesPerSec, format.wChannels, format.wBitsPerSample ); // Open the WAVE for output: using (var wav = File.Open(outWaveFile, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var bs = new BufferedStream(wav)) using (var bw = new BinaryWriter(bs)) { var header = new WaveHeader(); // Write the header bw.Write(header.sGroupID.ToCharArray()); bw.Write(header.dwFileLength); bw.Write(header.sRiffType.ToCharArray()); // Write the format chunk bw.Write(format.sChunkID.ToCharArray()); bw.Write(format.dwChunkSize); bw.Write(format.wFormatTag); bw.Write(format.wChannels); bw.Write(format.dwSamplesPerSec); bw.Write(format.dwAvgBytesPerSec); bw.Write(format.wBlockAlign); bw.Write(format.wBitsPerSample); var data = new WaveDataChunk(); // Write the data chunk bw.Write(data.sChunkID.ToCharArray()); bw.Write(data.dwChunkSize); double lastSample = sample; int nextBeatTick = 0; int note = 0; int tick = 0; using (var en = timeChanges.GetEnumerator()) { MidiEvent nextEvent; bool haveKeyOrTempoChange = en.MoveNext(); var me = en.Current; nextEvent = me.ev; while (tick < lastEvent.AbsoluteTicks) { for (; tick < nextEvent.AbsoluteTicks; ++tick) { // Start a click at this tick: if (tick == nextBeatTick) { int beat = note; //Debug.WriteLine("Click at tick {0,7}, sample {1,12:#######0.00}, beat {2,2}", tick, sample, beat); // Copy in a click: double vol = doAttenuateBeat(beat) ? 0.3d : 1d; // Silence until start of this click: int x = (int)((long)sample - (long)lastSample); for (; x > 0; --x) { for (int j = 0; j < channels; ++j) bw.Write((short)0); } // Choose the click sound based on the beat: short[,] click = (beat == 0) ? pinglo : pinghi; int clickLength = (beat == 0) ? pingloLength : pinghiLength; // Write the portion of the click if we missed the start: int samplesWritten = 0; long delta = x; for (x = -x; x < clickLength; ++x, ++samplesWritten) { int y = (int)((double)x * 48000d / (double)samplesPerSec); if (y >= clickLength) break; for (int j = 0; j < channels; ++j) bw.Write((short)(click[y, j] * vol)); } lastSample = sample + samplesWritten + delta; // Set next beat tick: nextBeatTick = tick + beatTicks; note = (note + 1) % getNumerator(); } sample += samplesPerTick; } if (haveKeyOrTempoChange) { if (me.mm.MetaType == MetaType.Tempo) { currentTempo = new TempoMessage(me.mm); calcUsecPerTick(); Console.WriteLine( "{0,9}: tempo {1,8:###0.000} bpm = {2,9:#,###,##0} usec/qtr", me.ev.AbsoluteTicks, 500000d / currentTempo.MicrosecondsPerQuarter * 120, currentTempo.MicrosecondsPerQuarter ); } else { currentTimeSignature = new TimeSignatureMessage(me.mm); calcBeatTicks(); #if false // NOTE: Assume key change is on a beat tick; force a reset of beats anyway. //nextBeatTick = tick; //note = 0; #endif Console.WriteLine( "{0,9}: meter {1,2}/{2,-2} treating as {3,2}/{4,-2}", me.ev.AbsoluteTicks, currentTimeSignature.Numerator, currentTimeSignature.Denominator, getNumerator(), getDenominator() ); } haveKeyOrTempoChange = en.MoveNext(); if (haveKeyOrTempoChange) { me = en.Current; nextEvent = me.ev; } else { me = null; nextEvent = lastEvent; } } } } // Write RIFF file size: bw.Seek(4, SeekOrigin.Begin); uint filesize = (uint)wav.Length; bw.Write(filesize - 8); // Write "data" chunk size: bw.Seek(0x28, SeekOrigin.Begin); bw.Write(filesize - 0x2C); } Console.WriteLine("Click track written to '{0}'", outWaveFile); Console.WriteLine( "Sample rate = {0,6} Hz; Channels = {1,1}; BitsPerSample = {2,2}", format.dwSamplesPerSec, format.wChannels, format.wBitsPerSample ); }
public static extern int waveOutWrite(IntPtr hwo, ref WaveHeader pwh, int cbwh);
// made non-static so that playing can be stopped here private void Callback(IntPtr hWaveOut, WaveInterop.WaveMessage uMsg, IntPtr dwUser, WaveHeader wavhdr, IntPtr dwReserved) { if (uMsg == WaveInterop.WaveMessage.WaveOutDone) { // check that we're not here through pressing stop var hBuffer = (GCHandle)wavhdr.userData; var buffer = (WaveOutBuffer)hBuffer.Target; lock (actionQueue) { actionQueue.Enqueue(new WaveOutAction(WaveOutFunction.BufferDone, buffer)); workAvailable.Set(); } // n.b. this was wrapped in an exception handler, but bug should be fixed now } }
/// <summary> /// 文本合成 /// </summary> /// <param name="text"></param> /// <param name="param"></param> /// <param name="waveFile"></param> public void TextToSpeech(string text,string param,string waveFile) { byte[] bytes = null; int ret = 0; try { sessionID=Marshal.PtrToStringAuto(MSCDLL.QTTSSessionBegin(param,ref ret)); //UnityEngine.Debug.Log(sessionID); if (ret!=(int)ErrorCode.MSP_SUCCESS) { if (onErrorEvent!=null) onErrorEvent.Invoke("初始化出错."+ret); return; } // UnityEngine.Debug.Log("初始化成功"); ret=MSCDLL.QTTSTextPut(sessionID,text,(uint)Encoding.Unicode.GetByteCount(text),string.Empty); if (ret!=(int)ErrorCode.MSP_SUCCESS) { if (onErrorEvent!=null) onErrorEvent.Invoke("发生数据出错."+ret); return; } // UnityEngine.Debug.Log("发生数据成功"); IntPtr audioData; uint audioLen = 0; SynthStatus synthStatus = SynthStatus.MSP_TTS_FLAG_STILL_HAVE_DATA; using (MemoryStream ms = new MemoryStream()) { ms.Write(new byte[44],0,44); while (synthStatus==SynthStatus.MSP_TTS_FLAG_STILL_HAVE_DATA) { audioData = MSCDLL.QTTSAudioGet(sessionID,ref audioLen,ref synthStatus,ref ret); if (audioData!=IntPtr.Zero) { byte[] data = new byte[audioLen]; Marshal.Copy(audioData,data,0,data.Length); ms.Write(data,0,data.Length); if (synthStatus==SynthStatus.MSP_TTS_FLAG_DATA_END||ret!=(int)ErrorCode.MSP_SUCCESS) { if (ret!=(int)ErrorCode.MSP_SUCCESS) { if (onErrorEvent!=null) onErrorEvent.Invoke("下载文件错误."+ret); return; } break; } } Thread.Sleep(150); } //UnityEngine.Debug.Log("wav header"); WaveHeader header = GetWaveHeader((int)ms.Length-44); byte[] headerByte = StructToBytes(header); ms.Position=0; ms.Write(headerByte,0,headerByte.Length); bytes=ms.ToArray(); ms.Close(); } if (waveFile!=null) { if (File.Exists(waveFile)) { File.Delete(waveFile); } File.WriteAllBytes(waveFile,bytes); } } catch (Exception ex) { if (onErrorEvent!=null) onErrorEvent.Invoke("Error:"+ex.Message); return; } finally { ret =MSCDLL.QTTSSessionEnd(sessionID,""); if (ret !=(int)ErrorCode.MSP_SUCCESS) { if (onErrorEvent!=null) onErrorEvent.Invoke("结束时出错."+ret); } else { if (onFinishEvent!=null) onFinishEvent.Invoke(text,bytes); } } }
/** * Saves selected frame span to a new file. * * @param filename where to save frames * @param begin number of the first frame * @param end number of the last frame * @throw FormatException not allowed to save 8b-mono files */ public void SaveFrames(string filename, int begin, int end) { if (1 == hdr.Channels && 8 == hdr.BitsPerSamp) { throw new FormatException("Save error: 8-bit mono files are not supported yet!"); } int samples = GetSamplesPerFrame(); // calculate the boundaries of a fragment of the source channel // which correspond to given frame numbers int startPos = (int)(begin * samples * (1 - overlap)); int endPos = (int)((end + 1) * samples * (1 - overlap) + samples * overlap); if (endPos > LChTab.Count) endPos = LChTab.Count; // number of data bytes in the resulting wave file UInt32 waveSize = (UInt32) (endPos - startPos) * hdr.BytesPerSamp; // prepare a new header and write it to file stream WaveHeader newHdr = new WaveHeader(); //std.strncpy(newHdr.RIFF, hdr.RIFF, 4); newHdr.DataLength = (UInt32) (waveSize + newHdr.WaveHeaderSize); //std.strncpy(newHdr.WAVE, hdr.WAVE, 4); //std.strncpy(newHdr.fmt_, hdr.fmt_, 4); newHdr.SubBlockLength = hdr.SubBlockLength; newHdr.formatTag = hdr.formatTag; newHdr.Channels = hdr.Channels; newHdr.SampFreq = hdr.SampFreq; newHdr.BytesPerSec = hdr.BytesPerSec; newHdr.BytesPerSamp = hdr.BytesPerSamp; newHdr.BitsPerSamp = hdr.BitsPerSamp; //std.strncpy(newHdr.data, hdr.data, 4); newHdr.WaveSize = waveSize; BinaryFile fs = new BinaryFile(filename); //fs.write((string) newHdr, sizeof(WaveHeader)); fs.Write(newHdr.RIFF); fs.Write(newHdr.DataLength); fs.Write(newHdr.WAVE); fs.Write(newHdr.fmt_); fs.Write(newHdr.SubBlockLength); fs.Write(newHdr.formatTag); fs.Write(newHdr.Channels); fs.Write(newHdr.SampFreq); fs.Write(newHdr.BytesPerSec); fs.Write(newHdr.BytesPerSamp); fs.Write(newHdr.BitsPerSamp); fs.Write(newHdr.data); fs.Write(newHdr.WaveSize); // convert our data from source channels to a temporary buffer short[] data = new short[waveSize/2]; for (int i = startPos, di = 0; i < endPos; ++i, ++di) { if (16 == hdr.BitsPerSamp) { if (2 == hdr.Channels) { data[2 *di] = LChTab[i]; data[2 *di+1] = RChTab[i]; } else { data[di] = LChTab[i]; } } else { if (2 == hdr.Channels) { //data[di/2] = ((RChTab[i] + 128) << 8) | (LChTab[i] + 128); } } } // write the raw data to file and clean the buffer for (int i = 0; i < data.Length; i++) { fs.Write(data[i]); } fs.Close(); data = null; }
public unsafe static void Save(Song song, string filename, int sampleRate) { var advance = true; var tempoCounter = 0; var playPattern = 0; var playNote = 0; var speed = song.Speed; var wavBytes = new List <byte>(); var apuIndex = NesApu.APU_WAV_EXPORT; var dmcCallback = new NesApu.DmcReadDelegate(NesApu.DmcReadCallback); NesApu.NesApuInit(apuIndex, sampleRate, dmcCallback); NesApu.Reset(apuIndex); var channels = new ChannelState[5] { new SquareChannelState(apuIndex, 0), new SquareChannelState(apuIndex, 1), new TriangleChannelState(apuIndex, 2), new NoiseChannelState(apuIndex, 3), new DPCMChannelState(apuIndex, 4) }; for (int i = 0; i < 5; i++) { NesApu.NesApuEnableChannel(apuIndex, i, 1); } while (true) { // Advance to next note. if (advance) { foreach (var channel in channels) { channel.ProcessEffects(song, ref playPattern, ref playNote, ref speed, false); } foreach (var channel in channels) { channel.Advance(song, playPattern, playNote); } advance = false; } // Update envelopes + APU registers. foreach (var channel in channels) { channel.UpdateEnvelopes(); channel.UpdateAPU(); } NesApu.NesApuEndFrame(apuIndex); int numTotalSamples = NesApu.NesApuSamplesAvailable(apuIndex); byte[] samples = new byte[numTotalSamples * 2]; fixed(byte *ptr = &samples[0]) { NesApu.NesApuReadSamples(apuIndex, new IntPtr(ptr), numTotalSamples); } wavBytes.AddRange(samples); int dummy1 = 0; if (!PlayerBase.AdvanceTempo(song, speed, LoopMode.None, ref tempoCounter, ref playPattern, ref playNote, ref dummy1, ref advance)) { break; } } using (var file = new FileStream(filename, FileMode.Create)) { var header = new WaveHeader(); // RIFF WAVE Header header.chunkId[0] = (byte)'R'; header.chunkId[1] = (byte)'I'; header.chunkId[2] = (byte)'F'; header.chunkId[3] = (byte)'F'; header.format[0] = (byte)'W'; header.format[1] = (byte)'A'; header.format[2] = (byte)'V'; header.format[3] = (byte)'E'; // Format subchunk header.subChunk1Id[0] = (byte)'f'; header.subChunk1Id[1] = (byte)'m'; header.subChunk1Id[2] = (byte)'t'; header.subChunk1Id[3] = (byte)' '; header.audioFormat = 1; // FOR PCM header.numChannels = 1; // 1 for MONO, 2 for stereo header.sampleRate = sampleRate; // ie 44100 hertz, cd quality audio header.bitsPerSample = 16; // header.byteRate = header.sampleRate * header.numChannels * header.bitsPerSample / 8; header.blockAlign = (short)(header.numChannels * header.bitsPerSample / 8); // Data subchunk header.subChunk2Id[0] = (byte)'d'; header.subChunk2Id[1] = (byte)'a'; header.subChunk2Id[2] = (byte)'t'; header.subChunk2Id[3] = (byte)'a'; // All sizes for later: // chuckSize = 4 + (8 + subChunk1Size) + (8 + subChubk2Size) // subChunk1Size is constanst, i'm using 16 and staying with PCM // subChunk2Size = nSamples * nChannels * bitsPerSample/8 // Whenever a sample is added: // chunkSize += (nChannels * bitsPerSample/8) // subChunk2Size += (nChannels * bitsPerSample/8) header.subChunk1Size = 16; header.subChunk2Size = wavBytes.Count; header.chunkSize = 4 + (8 + header.subChunk1Size) + (8 + header.subChunk2Size); var headerBytes = new byte[sizeof(WaveHeader)]; Marshal.Copy(new IntPtr(&header), headerBytes, 0, headerBytes.Length); file.Write(headerBytes, 0, headerBytes.Length); file.Write(wavBytes.ToArray(), 0, wavBytes.Count); } }
public static extern int waveOutPrepareHeader(IntPtr hwo, ref WaveHeader pwh, int cbwh);
public static extern int waveInAddBuffer(IntPtr hwi, ref WaveHeader pwh, int cbwh);
public static extern int waveInUnprepareHeader(IntPtr hwi, ref WaveHeader pwh, int cbwh);