Запись Wav в файл - C#
Формулировка задачи:
Пишу на C#. Имеется написанный код для записи звука с микрофона в поток(исходник будет ниже). Мне надо сохранить его в файл формата Wav чтоб воспроизводилось в плеере (но если честно файл wav будет нужен для других целей)
Сам сломал голову!!! Если не сложно помогите)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using Microsoft.DirectX.DirectSound;
using Buffer = Microsoft.DirectX.DirectSound.Buffer;
namespace vs3
{
class Record
{
public static WaveFormat _waveFormat;
//свойство формат
public static WaveFormat waveFormat
{
get
{
return _waveFormat;
}
}
private static UInt16 sizeBufer = 22050;
private static MemoryStream stream;
private static MemoryStream tempStream;
//свойство размер
public static int Length
{
get
{
return (int)stream.Length;
}
}
public static byte[] Data
{
get
{
switch (regim)
{
case 0: break;
case 1: RecordStop(); break;
case 2: PlayStop(); break;
}
return stream.ToArray();
}
}
public static byte regim = 0;
private static Capture capture;
private static CaptureBufferDescription captureBuffDesc;
private static CaptureBuffer recordBuff;
private static AutoResetEvent autoResetEventRec;
private static BufferPositionNotify[] positionNotifyRec;
private static Notify notifyRec;
private static Thread threadRec;
private static Device device;
private static Buffer playBuff;
private static BufferDescription secondBuffDesc;
private static System.Windows.Forms.Control control = null;
private static Thread threadPlay;
private static AutoResetEvent autoResetEventPlay;
private static BufferPositionNotify[] positionNotifyPlay;
private static Notify notifyPlay;
public static void Create(System.Windows.Forms.Control _control)
{
control = _control;
SetWaveFormat();
SetTempStream();
SetPlayBuff();
SetRecordBuff();
SetNotifyPlay();
SetNotifyRecord();
}
private static void SetTempStream()
{
ushort i, n = (ushort)(sizeBufer);
byte[] temp = new byte[n];
if (_waveFormat.BitsPerSample == 8)
{
for (i = 0; i < n; i++) temp[i] = 127;
tempStream = new MemoryStream(temp);
return;
}
if (_waveFormat.BitsPerSample == 16)
{
for (i = 0; i < n; i++) temp[i] = 0;
tempStream = new MemoryStream(temp);
return;
}
}
private static void SetWaveFormat()
{
_waveFormat = new WaveFormat();
_waveFormat.BitsPerSample = 8;
_waveFormat.BlockAlign = 1;
_waveFormat.Channels = 1;
_waveFormat.AverageBytesPerSecond = 22050;
_waveFormat.SamplesPerSecond = 22050;
_waveFormat.FormatTag = WaveFormatTag.Pcm;
}
private static void SetRecordBuff()
{
capture = new Capture();
captureBuffDesc = new CaptureBufferDescription();
captureBuffDesc.BufferBytes = sizeBufer;
captureBuffDesc.Format = _waveFormat;
recordBuff = new CaptureBuffer(captureBuffDesc, capture);
}
private static void SetNotifyRecord()
{
autoResetEventRec = new AutoResetEvent(false);
positionNotifyRec = new BufferPositionNotify[2];
positionNotifyRec[0].Offset = sizeBufer / 2 - 1;
positionNotifyRec[0].EventNotifyHandle = autoResetEventRec.SafeWaitHandle.DangerousGetHandle();
positionNotifyRec[1].Offset = sizeBufer - 1;
positionNotifyRec[1].EventNotifyHandle = autoResetEventRec.SafeWaitHandle.DangerousGetHandle();
notifyRec = new Notify(recordBuff);
notifyRec.SetNotificationPositions(positionNotifyRec, 2);
}
private static void Recording()
{
int offset = 0;
int a, b;
recordBuff.GetCurrentPosition(out a, out b);
if (a == 0) { offset = sizeBufer / 2; b = sizeBufer / 2; }
else if (a < sizeBufer / 2) { offset = sizeBufer / 2; b = sizeBufer / 2 - a; }
else { offset = 0; b = sizeBufer - a; }
recordBuff.Start(true);
autoResetEventRec.WaitOne(Timeout.Infinite, true);
recordBuff.Read(a, stream, b, LockFlag.None);
for (; ; )
{
autoResetEventRec.WaitOne(Timeout.Infinite, true);
recordBuff.Read(offset, stream, sizeBufer / 2, LockFlag.None);
offset = (offset + sizeBufer / 2) % (sizeBufer);
}
}
private static void RecordStart()
{
switch (regim)
{
case 0: break;
case 1: RecordStop(); break;
case 2: PlayStop(); break;
}
regim = 1;
stream = new MemoryStream();
threadRec = new Thread(new ThreadStart(Recording));
threadRec.Start();
}
private static void RecordStop()
{
if (regim != 1) return;
int a, b;
threadRec.Abort();
recordBuff.Stop();
recordBuff.GetCurrentPosition(out a, out b);
if (a == sizeBufer / 2 || a == sizeBufer) { regim = 0; return; }
if (a < sizeBufer / 2)
{
recordBuff.Read(0, stream, a, LockFlag.None);
}
else
{
recordBuff.Read(sizeBufer / 2, stream, a - sizeBufer / 2, LockFlag.None);
}
regim = 0;
}
private static void SetPlayBuff()
{
device = new Device();
device.SetCooperativeLevel(control, CooperativeLevel.Priority);
secondBuffDesc = new BufferDescription();
secondBuffDesc.Format = _waveFormat;
secondBuffDesc.BufferBytes = sizeBufer;
secondBuffDesc.LocateInSoftware = true;
secondBuffDesc.ControlPositionNotify = true;
secondBuffDesc.ControlFrequency = true;
secondBuffDesc.ControlPan = true;
secondBuffDesc.ControlVolume = true;
playBuff = new Buffer(secondBuffDesc, device);
}
private static void SetNotifyPlay()
{
autoResetEventPlay = new AutoResetEvent(false);
positionNotifyPlay = new BufferPositionNotify[2];
positionNotifyPlay[0].Offset = sizeBufer / 2 - 1;
positionNotifyPlay[0].EventNotifyHandle = autoResetEventPlay.SafeWaitHandle.DangerousGetHandle();
positionNotifyPlay[1].Offset = sizeBufer - 1;
positionNotifyPlay[1].EventNotifyHandle = autoResetEventPlay.SafeWaitHandle.DangerousGetHandle();
notifyPlay = new Notify(playBuff);
notifyPlay.SetNotificationPositions(positionNotifyPlay, 2);
}
private static void Playing()
{
uint i, num = (uint)(stream.Length / (sizeBufer / 2));
int offset, ostatok = (int)stream.Length % (sizeBufer / 2);
if (num < 2)
{
playBuff.Write(0, stream, (int)stream.Length, LockFlag.None);
playBuff.Write((int)stream.Length, tempStream, sizeBufer - (int)stream.Length, LockFlag.None);
playBuff.Play(0, BufferPlayFlags.Default);
return;
}
playBuff.Write(0, stream, sizeBufer, LockFlag.None);
playBuff.Play(0, BufferPlayFlags.Looping);
autoResetEventPlay.WaitOne(Timeout.Infinite, true);
for (offset = 0, i = 2; i <= num; i++)
{
if (i != num)
{
playBuff.Write(offset, stream, sizeBufer / 2, LockFlag.None);
}
else
{
playBuff.Write(offset, stream, ostatok, LockFlag.None);
playBuff.Write(offset + ostatok, tempStream, sizeBufer / 2 - ostatok, LockFlag.None);
}
offset = (offset + sizeBufer / 2) % sizeBufer;
autoResetEventPlay.WaitOne(Timeout.Infinite, true);
}
autoResetEventPlay.WaitOne(Timeout.Infinite, true);
playBuff.Stop();
regim = 0;
}
private static void PlayStart()
{
switch (regim)
{
case 0: break;
case 1: RecordStop(); break;
case 2: PlayStop(); break;
}
regim = 2;
stream.Position = 0;
playBuff.SetCurrentPosition(0);
tempStream.Position = 0;
threadPlay = new Thread(new ThreadStart(Playing));
threadPlay.Start();
}
private static void PlayStop()
{
if (regim == 2)
{
threadPlay.Abort();
playBuff.Stop();
regim = 0;
}
}
public static void Record1()
{
RecordStart();
}
public static void Play()
{
PlayStart();
}
public static int Stop()
{
switch (regim)
{
case 1: RecordStop(); return 1;
case 2: PlayStop(); return 2;
default: return 0;
}
}
public static int Save(string Name)
{
//Вот надо сюда вставить.написать что-то чтобы сохранить
return 0;
}
}
}Решение задачи: «Запись Wav в файл»
textual
Листинг программы
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace WavFormatCSharp
{
[StructLayout(LayoutKind.Sequential)]
// Структура, описывающая заголовок WAV файла.
internal class WavHeader
{
// WAV-формат начинается с RIFF-заголовка:
// Содержит символы "RIFF" в ASCII кодировке
// (0x52494646 в big-endian представлении)
public UInt32 ChunkId;
// 36 + subchunk2Size, или более точно:
// 4 + (8 + subchunk1Size) + (8 + subchunk2Size)
// Это оставшийся размер цепочки, начиная с этой позиции.
// Иначе говоря, это размер файла - 8, то есть,
// исключены поля chunkId и chunkSize.
public UInt32 ChunkSize;
// Содержит символы "WAVE"
// (0x57415645 в big-endian представлении)
public UInt32 Format;
// Формат "WAVE" состоит из двух подцепочек: "fmt " и "data":
// Подцепочка "fmt " описывает формат звуковых данных:
// Содержит символы "fmt "
// (0x666d7420 в big-endian представлении)
public UInt32 Subchunk1Id;
// 16 для формата PCM.
// Это оставшийся размер подцепочки, начиная с этой позиции.
public UInt32 Subchunk1Size;
// Аудио формат, полный список можно получить здесь [url]http://audiocoding.ru/wav_formats.txt[/url]
// Для PCM = 1 (то есть, Линейное квантование).
// Значения, отличающиеся от 1, обозначают некоторый формат сжатия.
public UInt16 AudioFormat;
// Количество каналов. Моно = 1, Стерео = 2 и т.д.
public UInt16 NumChannels;
// Частота дискретизации. 8000 Гц, 44100 Гц и т.д.
public UInt32 SampleRate;
// sampleRate * numChannels * bitsPerSample/8
public UInt32 ByteRate;
// numChannels * bitsPerSample/8
// Количество байт для одного сэмпла, включая все каналы.
public UInt16 BlockAlign;
// Так называемая "глубиная" или точность звучания. 8 бит, 16 бит и т.д.
public UInt16 BitsPerSample;
// Подцепочка "data" содержит аудио-данные и их размер.
// Содержит символы "data"
// (0x64617461 в big-endian представлении)
public UInt32 Subchunk2Id;
// numSamples * numChannels * bitsPerSample/8
// Количество байт в области данных.
public UInt32 Subchunk2Size;
// Далее следуют непосредственно Wav данные.
}
class Program
{
static void Main(string[] args)
{
var header = new WavHeader();
// Размер заголовка
var headerSize = Marshal.SizeOf(header);
var fileStream = new FileStream("Slipknot - Three Nil.wav", FileMode.Open, FileAccess.Read);
var buffer = new byte[headerSize];
fileStream.Read(buffer, 0, headerSize);
// Чтобы не считывать каждое значение заголовка по отдельности,
// воспользуемся выделением unmanaged блока памяти
var headerPtr = Marshal.AllocHGlobal(headerSize);
// Копируем считанные байты из файла в выделенный блок памяти
Marshal.Copy(buffer, 0, headerPtr, headerSize);
// Преобразовываем указатель на блок памяти к нашей структуре
Marshal.PtrToStructure(headerPtr, header);
// Выводим полученные данные
Console.WriteLine("Sample rate: {0}", header.SampleRate);
Console.WriteLine("Channels: {0}", header.NumChannels);
Console.WriteLine("Bits per sample: {0}", header.BitsPerSample);
// Посчитаем длительность воспроизведения в секундах
var durationSeconds = 1.0 * header.Subchunk2Size / (header.BitsPerSample / 8.0) / header.NumChannels / header.SampleRate;
var durationMinutes = (int)Math.Floor(durationSeconds / 60);
durationSeconds = durationSeconds - (durationMinutes * 60);
Console.WriteLine("Duration: {0:00}:{1:00}", durationMinutes, durationSeconds);
Console.ReadKey();
}
}
}