Code cleanup
This commit is contained in:
Родитель
5bb89f2f88
Коммит
53a5ac346e
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче