This commit is contained in:
Wiesław Šoltés 2012-11-20 20:43:43 +01:00
Родитель 5bb89f2f88
Коммит 53a5ac346e
2 изменённых файлов: 204 добавлений и 199 удалений

Просмотреть файл

@ -79,13 +79,15 @@ namespace SimpleWavSplitter
private static void GetWavHeader()
{
Microsoft.Win32.OpenFileDialog d = new Microsoft.Win32.OpenFileDialog();
d.Filter = "WAV Files (*.wav)|*.wav|All Files (*.*)|*.*";
d.FilterIndex = 0;
d.Multiselect = true;
if (d.ShowDialog() == true)
var dlg = new Microsoft.Win32.OpenFileDialog();
dlg.Filter = "WAV Files (*.wav)|*.wav|All Files (*.*)|*.*";
dlg.FilterIndex = 0;
dlg.Multiselect = true;
if (dlg.ShowDialog() == true)
{
string[] fileNames = d.FileNames;
string[] fileNames = dlg.FileNames;
foreach (string fileName in fileNames)
{
// parse WAV file header
@ -95,7 +97,7 @@ namespace SimpleWavSplitter
using (System.IO.FileStream f = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
// read WAV file header
WavFileHeader h = WavFileInfo.ReadFileHeader(f);
var h = WavFileInfo.ReadFileHeader(f);
// show WAV header
MessageBox.Show(
@ -117,211 +119,215 @@ namespace SimpleWavSplitter
private void SplitWavFiles()
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
var dlg = new Microsoft.Win32.OpenFileDialog();
dlg.Filter = "WAV Files (*.wav)|*.wav|All Files (*.*)|*.*";
dlg.FilterIndex = 0;
dlg.Multiselect = true;
if (dlg.ShowDialog() == true)
{
// reset window controls to defaults
progress.Value = 0;
SplitWavFiles(dlg.FileNames);
}
}
// create background worker
worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
private void SplitWavFiles(string[] dlgFileNames)
{
// reset window controls to defaults
progress.Value = 0;
string dlgFileName = string.Copy(dlg.FileName);
// create background worker
worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.DoWork += (s, args) =>
worker.DoWork += (s, args) =>
{
string[] fileNames = (string[])args.Argument;
long countBytesTotal = 0;
var sw = new System.Diagnostics.Stopwatch();
sw.Start();
foreach (string fileName in fileNames)
{
string[] fileNames = (string[])args.Argument;
long countBytesTotal = 0;
var sw = new System.Diagnostics.Stopwatch();
sw.Start();
foreach (string fileName in fileNames)
// parse WAV file header
try
{
// parse WAV file header
try
// update progress
Dispatcher.Invoke((Action)delegate()
{
// update progress
Dispatcher.Invoke((Action)delegate()
{
progress.Value = 0.0;
});
progress.Value = 0.0;
});
// bytes counter
long countBytes = 0;
// bytes counter
long countBytes = 0;
// create WAV file stream
var f = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
// create WAV file stream
var f = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
// read WAV file header
WavFileHeader h = WavFileInfo.ReadFileHeader(f);
// read WAV file header
WavFileHeader h = WavFileInfo.ReadFileHeader(f);
countBytes += h.HeaderSize;
countBytesTotal += h.HeaderSize;
countBytes += h.HeaderSize;
countBytesTotal += h.HeaderSize;
// print debug
System.Diagnostics.Debug.Print(string.Format("FileName: {0}, Header:\n{1}",
fileName,
h.ToString()));
// print debug
System.Diagnostics.Debug.Print(string.Format("FileName: {0}, Header:\n{1}",
fileName,
h.ToString()));
// create output filenames
string filePath = dlgFileName.Remove(fileName.Length - System.IO.Path.GetFileName(fileName).Length);
string fileNameOnly = System.IO.Path.GetFileNameWithoutExtension(fileName);
string[] outputFileNames = new string[h.NumChannels];
WavChannel[] channels = new WavChannel[h.NumChannels];
int countChannels = 0;
// create output filenames
string filePath = fileName.Remove(fileName.Length - System.IO.Path.GetFileName(fileName).Length);
string fileNameOnly = System.IO.Path.GetFileNameWithoutExtension(fileName);
string[] outputFileNames = new string[h.NumChannels];
WavChannel[] channels = new WavChannel[h.NumChannels];
int countChannels = 0;
// set channel names
if (h.IsExtensible == false)
{
for (int c = 0; c < h.NumChannels; c++)
{
string chNum = (c + 1).ToString("D2");
WavChannel ch = new WavChannel("Channel" + chNum, "CH" + chNum, 0);
channels[c] = ch;
}
}
else
{
foreach (WavChannel ch in WavFileHeader.WavMultiChannelTypes)
{
if (((uint)ch.Mask & h.ChannelMask) != 0)
channels[countChannels++] = ch;
}
}
// join: input path + input file name without extension + ''. + short channel name + '.wav' extension
for (int p = 0; p < channels.Count(); p++)
{
outputFileNames[p] = filePath + fileNameOnly + "." + channels[p].ShortName + ".wav";
}
// create data buffers
long dataSize = h.Subchunk2Size;
int bufferSize = (int)h.ByteRate;
int channelBufferSize = (int)(h.ByteRate / h.NumChannels);
byte[] buffer = new byte[bufferSize];
byte[][] channelBuffer = new byte[h.NumChannels][];
int copySize = h.BlockAlign / h.NumChannels;
// create output files
System.IO.FileStream[] outputFile = new System.IO.FileStream[h.NumChannels];
// each mono output file has the same header
WavFileHeader monoFileHeader = WavFileInfo.GetMonoWavFileHeader(h);
// write output files header and create temp buffer for each channel
// set channel names
if (h.IsExtensible == false)
{
for (int c = 0; c < h.NumChannels; c++)
{
channelBuffer[c] = new byte[channelBufferSize];
outputFile[c] = new System.IO.FileStream(outputFileNames[c], System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite);
WavFileInfo.WriteFileHeader(outputFile[c], monoFileHeader);
string chNum = (c + 1).ToString("D2");
var ch = new WavChannel("Channel" + chNum, "CH" + chNum, 0);
channels[c] = ch;
}
// cleanup action
var cleanUp = new Action(() =>
}
else
{
foreach (WavChannel ch in WavFileHeader.WavMultiChannelTypes)
{
// close input file
f.Close();
f.Dispose();
if (((uint)ch.Mask & h.ChannelMask) != 0)
channels[countChannels++] = ch;
}
}
// close output files
for (int c = 0; c < h.NumChannels; c++)
{
outputFile[c].Close();
outputFile[c].Dispose();
}
});
// join: input path + input file name without extension + ''. + short channel name + '.wav' extension
for (int p = 0; p < channels.Count(); p++)
{
outputFileNames[p] = filePath + fileNameOnly + "." + channels[p].ShortName + ".wav";
}
// read data from input file and write to multiple-output files
for (long i = 0; i < dataSize; i += bufferSize)
// create data buffers
long dataSize = h.Subchunk2Size;
int bufferSize = (int)h.ByteRate;
int channelBufferSize = (int)(h.ByteRate / h.NumChannels);
byte[] buffer = new byte[bufferSize];
byte[][] channelBuffer = new byte[h.NumChannels][];
int copySize = h.BlockAlign / h.NumChannels;
// create output files
System.IO.FileStream[] outputFile = new System.IO.FileStream[h.NumChannels];
// each mono output file has the same header
WavFileHeader mh = WavFileInfo.GetMonoWavFileHeader(h);
// write output files header and create temp buffer for each channel
for (int c = 0; c < h.NumChannels; c++)
{
channelBuffer[c] = new byte[channelBufferSize];
outputFile[c] = new System.IO.FileStream(outputFileNames[c], System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite);
WavFileInfo.WriteFileHeader(outputFile[c], mh);
}
// cleanup action
var cleanUp = new Action(() =>
{
// close input file
f.Close();
f.Dispose();
// close output files
for (int c = 0; c < h.NumChannels; c++)
{
int n = f.Read(buffer, 0, bufferSize);
if (n > 0)
outputFile[c].Close();
outputFile[c].Dispose();
}
});
// read data from input file and write to multiple-output files
for (long i = 0; i < dataSize; i += bufferSize)
{
int n = f.Read(buffer, 0, bufferSize);
if (n > 0)
{
// split channel data
int[] count = new int[h.NumChannels];
for (int j = 0; j < n; j += h.BlockAlign)
{
// split channel data
int[] count = new int[h.NumChannels];
for (int j = 0; j < n; j += h.BlockAlign)
{
for (int c = 0; c < h.NumChannels; c++)
{
for (int k = 0; k < copySize; k++)
{
channelBuffer[c][count[c]++] = buffer[j + (c * copySize) + k];
}
}
}
// write single channel data to a file
for (int c = 0; c < h.NumChannels; c++)
{
outputFile[c].Write(channelBuffer[c], 0, count[c]);
for (int k = 0; k < copySize; k++)
{
channelBuffer[c][count[c]++] = buffer[j + (c * copySize) + k];
}
}
// cancel background job
if (worker.CancellationPending)
{
cleanUp();
// cancel job
args.Cancel = true;
return;
}
// update stats
countBytes += n;
countBytesTotal += n;
// update progress
Dispatcher.Invoke((Action)delegate()
{
progress.Value = ((double)countBytes / (double)f.Length) * 100;
});
}
// write single channel data to a file
for (int c = 0; c < h.NumChannels; c++)
{
outputFile[c].Write(channelBuffer[c], 0, count[c]);
}
// cancel background job
if (worker.CancellationPending)
{
cleanUp();
// cancel job
args.Cancel = true;
return;
}
// update stats
countBytes += n;
countBytesTotal += n;
// update progress
Dispatcher.Invoke((Action)delegate()
{
progress.Value = ((double)countBytes / (double)f.Length) * 100;
});
}
}
cleanUp();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
cleanUp();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
sw.Stop();
sw.Stop();
args.Result = new Tuple<TimeSpan,long>(sw.Elapsed, countBytesTotal);
};
args.Result = new Tuple<TimeSpan, long>(sw.Elapsed, countBytesTotal);
};
worker.RunWorkerCompleted += (s, args) =>
worker.RunWorkerCompleted += (s, args) =>
{
if (args.Cancelled == false)
{
if (args.Cancelled == false)
{
//SplitWorkResult result = (SplitWorkResult)args.Result;
Tuple<TimeSpan,long> result = (Tuple<TimeSpan,long>)args.Result;
//SplitWorkResult result = (SplitWorkResult)args.Result;
Tuple<TimeSpan, long> result = (Tuple<TimeSpan, long>)args.Result;
string stats = string.Format("Total data bytes processed: {0} ({1} MB)\nTotal elapsed time: {2}",
result.Item2,
Math.Round((double)result.Item2 / (1024 * 1024), 1),
result.Item1);
string stats = string.Format("Total data bytes processed: {0} ({1} MB)\nTotal elapsed time: {2}",
result.Item2,
Math.Round((double)result.Item2 / (1024 * 1024), 1),
result.Item1);
// show statistics to user
MessageBox.Show(stats, "Done", MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
progress.Value = 0;
}
};
// show statistics to user
MessageBox.Show(stats, "Done", MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
progress.Value = 0;
}
};
worker.RunWorkerAsync(dlg.FileNames);
}
worker.RunWorkerAsync(dlgFileNames);
}
private void CancelSplitWorker()

Просмотреть файл

@ -23,11 +23,12 @@ namespace WavFile
/// <returns></returns>
public static WavFileHeader ReadFileHeader(System.IO.FileStream f)
{
WavFileHeader h = new WavFileHeader();
var h = new WavFileHeader();
h.HeaderSize = 0;
// read WAV header
System.IO.BinaryReader b = new System.IO.BinaryReader(f);
var b = new System.IO.BinaryReader(f);
// WAVE
h.ChunkID = b.ReadUInt32(); // 0x46464952, "RIFF"
@ -148,7 +149,7 @@ namespace WavFile
public static void WriteFileHeader(System.IO.FileStream f, WavFileHeader h)
{
// write WAV header
System.IO.BinaryWriter b = new System.IO.BinaryWriter(f);
var b = new System.IO.BinaryWriter(f);
// WAVE
b.Write((UInt32)0x46464952); // 0x46464952, "RIFF"
@ -197,42 +198,40 @@ namespace WavFile
public static WavFileHeader GetMonoWavFileHeader(WavFileHeader h)
{
// each mono output file has the same header
WavFileHeader monoFileHeader = new WavFileHeader();
var mh = new WavFileHeader();
// WAVE
monoFileHeader.ChunkID = (UInt32)0x46464952; // 0x46464952, "RIFF"
monoFileHeader.ChunkSize = 36 + (h.Subchunk2Size / h.NumChannels); // 36 + SubChunk2Size, 4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
monoFileHeader.Format = (UInt32)0x45564157; // 0x45564157, "WAVE"
mh.ChunkID = (UInt32)0x46464952; // 0x46464952, "RIFF"
mh.ChunkSize = 36 + (h.Subchunk2Size / h.NumChannels); // 36 + SubChunk2Size, 4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
mh.Format = (UInt32)0x45564157; // 0x45564157, "WAVE"
// fmt
monoFileHeader.Subchunk1ID = (UInt32)0x20746d66; // 0x20746d66, "fmt "
monoFileHeader.Subchunk1Size = 16; // 16 for PCM, 40 for WAVEFORMATEXTENSIBLE
monoFileHeader.AudioFormat = (UInt16)1; // PCM = 1, WAVEFORMATEXTENSIBLE.SubFormat = 0xFFFE
monoFileHeader.NumChannels = (UInt16)1; // Mono = 1, Stereo = 2, etc.
monoFileHeader.SampleRate = h.SampleRate; // 8000, 44100, etc.
monoFileHeader.ByteRate = (UInt32)((h.SampleRate * 1 * h.BitsPerSample) / 8); // SampleRate * NumChannels * BitsPerSample/8
monoFileHeader.BlockAlign = (UInt16)((1 * h.BitsPerSample) / 8); // NumChannels * BitsPerSample/8
monoFileHeader.BitsPerSample = h.BitsPerSample; // 8 bits = 8, 16 bits = 16, etc.
mh.Subchunk1ID = (UInt32)0x20746d66; // 0x20746d66, "fmt "
mh.Subchunk1Size = 16; // 16 for PCM, 40 for WAVEFORMATEXTENSIBLE
mh.AudioFormat = (UInt16)1; // PCM = 1, WAVEFORMATEXTENSIBLE.SubFormat = 0xFFFE
mh.NumChannels = (UInt16)1; // Mono = 1, Stereo = 2, etc.
mh.SampleRate = h.SampleRate; // 8000, 44100, etc.
mh.ByteRate = (UInt32)((h.SampleRate * 1 * h.BitsPerSample) / 8); // SampleRate * NumChannels * BitsPerSample/8
mh.BlockAlign = (UInt16)((1 * h.BitsPerSample) / 8); // NumChannels * BitsPerSample/8
mh.BitsPerSample = h.BitsPerSample; // 8 bits = 8, 16 bits = 16, etc.
// extensible
monoFileHeader.ExtraParamSize = (UInt16)0;
monoFileHeader.ChannelMask = (UInt32)0;
monoFileHeader.GuidSubFormat = new Guid();
mh.ExtraParamSize = (UInt16)0;
mh.ChannelMask = (UInt32)0;
mh.GuidSubFormat = new Guid();
// data
monoFileHeader.Subchunk2ID = (UInt32)0x61746164; // 0x61746164, "data"
monoFileHeader.Subchunk2Size = (h.Subchunk2Size / h.NumChannels); // NumSamples * NumChannels * BitsPerSample/8
mh.Subchunk2ID = (UInt32)0x61746164; // 0x61746164, "data"
mh.Subchunk2Size = (h.Subchunk2Size / h.NumChannels); // NumSamples * NumChannels * BitsPerSample/8
// info
monoFileHeader.IsExtensible = false;
monoFileHeader.HeaderSize = 44;
monoFileHeader.TotalSamples = (long)((double)monoFileHeader.Subchunk2Size / ((double)monoFileHeader.NumChannels * (double)monoFileHeader.BitsPerSample / 8));
monoFileHeader.Duration = (1 / (double)monoFileHeader.SampleRate) * (double)monoFileHeader.TotalSamples;
mh.IsExtensible = false;
mh.HeaderSize = 44;
mh.TotalSamples = (long)((double)mh.Subchunk2Size / ((double)mh.NumChannels * (double)mh.BitsPerSample / 8));
mh.Duration = (1 / (double)mh.SampleRate) * (double)mh.TotalSamples;
return monoFileHeader;
return mh;
}
}
#endregion