make discohawk extractor reuse ffmpeg code from disc system and encode raw pcm to remove dependency on wavefile headers libs
This commit is contained in:
parent
1d0e995546
commit
290cf76223
|
@ -47,7 +47,7 @@ namespace BizHawk.DiscSystem
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string Run(params string[] args)
|
public string Run(params string[] args)
|
||||||
{
|
{
|
||||||
args = Escape(args);
|
args = Escape(args);
|
||||||
StringBuilder sbCmdline = new StringBuilder();
|
StringBuilder sbCmdline = new StringBuilder();
|
||||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using BizHawk.DiscSystem;
|
using BizHawk.DiscSystem;
|
||||||
using WaveLibrary;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
@ -21,42 +20,29 @@ namespace BizHawk
|
||||||
if (track.TrackType != ETrackType.Audio)
|
if (track.TrackType != ETrackType.Audio)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var wave = new WaveFile(2, 16, 44100);
|
|
||||||
var waveData = new byte[track.length_aba * 2352];
|
var waveData = new byte[track.length_aba * 2352];
|
||||||
int startLba = track.Indexes[1].LBA;
|
int startLba = track.Indexes[1].LBA;
|
||||||
for (int sector = 0; sector < track.length_aba; sector++)
|
for (int sector = 0; sector < track.length_aba; sector++)
|
||||||
disc.ReadLBA_2352(startLba + sector, waveData, sector * 2352);
|
disc.ReadLBA_2352(startLba + sector, waveData, sector * 2352);
|
||||||
|
|
||||||
wave.SetData(waveData, waveData.Length / 4);
|
string tempfile = Path.GetTempFileName();
|
||||||
string waveFilePath = Path.Combine(path, "__temp.wav");
|
|
||||||
wave.WriteFile(waveFilePath);
|
|
||||||
|
|
||||||
Encode(waveFilePath, string.Format("{0} - Track {1:D2}.mp3", Path.Combine(path, filebase), track.num));
|
try
|
||||||
|
{
|
||||||
File.Delete(waveFilePath);
|
File.WriteAllBytes(tempfile, waveData);
|
||||||
|
Encode(tempfile, string.Format("{0} - Track {1:D2}.mp3", Path.Combine(path, filebase), track.num));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
File.Delete(tempfile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Encode(string wavePath, string mp3Path)
|
static void Encode(string wavePath, string mp3Path)
|
||||||
{
|
{
|
||||||
var args = Escape("-i", wavePath, "-ab", "192k", mp3Path);
|
var ffmpeg = new FFMpeg();
|
||||||
|
ffmpeg.Run("-f", "s16le", "-ar", "44100", "-ac", "2", "-i", wavePath, "-f", "mp3", "-ab", "192k", mp3Path);
|
||||||
StringBuilder sbCmdline = new StringBuilder();
|
|
||||||
for (int i = 0; i < args.Length; i++)
|
|
||||||
{
|
|
||||||
sbCmdline.Append(args[i]);
|
|
||||||
if (i != args.Length - 1) sbCmdline.Append(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessStartInfo oInfo = new ProcessStartInfo(FFmpegPath, sbCmdline.ToString());
|
|
||||||
oInfo.UseShellExecute = false;
|
|
||||||
oInfo.CreateNoWindow = true;
|
|
||||||
oInfo.RedirectStandardOutput = true;
|
|
||||||
oInfo.RedirectStandardError = true;
|
|
||||||
|
|
||||||
Process proc = System.Diagnostics.Process.Start(oInfo);
|
|
||||||
proc.WaitForExit();
|
|
||||||
string result = proc.StandardError.ReadToEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static string[] Escape(params string[] args)
|
static string[] Escape(params string[] args)
|
||||||
|
|
|
@ -94,10 +94,6 @@
|
||||||
<Compile Include="ProgressDialog.Designer.cs">
|
<Compile Include="ProgressDialog.Designer.cs">
|
||||||
<DependentUpon>ProgressDialog.cs</DependentUpon>
|
<DependentUpon>ProgressDialog.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Wave\WavedataSubChunk.cs" />
|
|
||||||
<Compile Include="Wave\WaveFile.cs" />
|
|
||||||
<Compile Include="Wave\WavefmtSubChunk.cs" />
|
|
||||||
<Compile Include="Wave\WaveHeader.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
/* Wave File Library
|
|
||||||
* A simple library to write a wave file
|
|
||||||
*
|
|
||||||
* Garrett Hoofman
|
|
||||||
* 10/21/08
|
|
||||||
* http://www.visionsofafar.com
|
|
||||||
* */
|
|
||||||
|
|
||||||
/* Wave File Format
|
|
||||||
Reference : http://ccrma.stanford.edu/CCRMA/Courses/422/projects/WaveFormat/
|
|
||||||
The canonical WAVE format starts with the RIFF header:
|
|
||||||
0 4 ChunkID Contains the letters "RIFF" in ASCII form
|
|
||||||
(0x52494646 big-endian form).
|
|
||||||
4 4 ChunkSize 36 + SubChunk2Size, or more precisely:
|
|
||||||
4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
|
|
||||||
This is the size of the rest of the chunk
|
|
||||||
following this number. This is the size of the
|
|
||||||
entire file in bytes minus 8 bytes for the
|
|
||||||
two fields not included in this count:
|
|
||||||
ChunkID and ChunkSize.
|
|
||||||
8 4 Format Contains the letters "WAVE"
|
|
||||||
(0x57415645 big-endian form).
|
|
||||||
|
|
||||||
The "WAVE" format consists of two subchunks: "fmt " and "data":
|
|
||||||
The "fmt " subchunk describes the sound data's format:
|
|
||||||
12 4 Subchunk1ID Contains the letters "fmt "
|
|
||||||
(0x666d7420 big-endian form).
|
|
||||||
16 4 Subchunk1Size 16 for PCM. This is the size of the
|
|
||||||
rest of the Subchunk which follows this number.
|
|
||||||
20 2 AudioFormat PCM = 1 (i.e. Linear quantization)
|
|
||||||
Values other than 1 indicate some
|
|
||||||
form of compression.
|
|
||||||
22 2 NumChannels Mono = 1, Stereo = 2, etc.
|
|
||||||
24 4 SampleRate 8000, 44100, etc.
|
|
||||||
28 4 ByteRate == SampleRate * NumChannels * BitsPerSample/8
|
|
||||||
32 2 BlockAlign == NumChannels * BitsPerSample/8
|
|
||||||
The number of bytes for one sample including
|
|
||||||
all channels. I wonder what happens when
|
|
||||||
this number isn't an integer?
|
|
||||||
34 2 BitsPerSample 8 bits = 8, 16 bits = 16, etc.
|
|
||||||
2 ExtraParamSize if PCM, then doesn't exist
|
|
||||||
X ExtraParams space for extra parameters
|
|
||||||
|
|
||||||
The "data" subchunk contains the size of the data and the actual sound:
|
|
||||||
36 4 Subchunk2ID Contains the letters "data"
|
|
||||||
(0x64617461 big-endian form).
|
|
||||||
40 4 Subchunk2Size == NumSamples * NumChannels * BitsPerSample/8
|
|
||||||
This is the number of bytes in the data.
|
|
||||||
You can also think of this as the size
|
|
||||||
of the read of the subchunk following this
|
|
||||||
number.
|
|
||||||
44 * Data The actual sound data.
|
|
||||||
*/
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace WaveLibrary
|
|
||||||
{
|
|
||||||
public class WaveFile
|
|
||||||
{
|
|
||||||
WaveHeader header;
|
|
||||||
WavefmtSubChunk fmt;
|
|
||||||
WavedataSubChunk data;
|
|
||||||
|
|
||||||
public WaveFile(int channels, int bitsPerSample, int sampleRate)
|
|
||||||
{
|
|
||||||
header = new WaveHeader();
|
|
||||||
fmt = new WavefmtSubChunk(channels, bitsPerSample, sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetData(byte[] SoundData, int numSamples)
|
|
||||||
{
|
|
||||||
data = new WavedataSubChunk(numSamples, fmt.NumChannels, fmt.BitsPerSample, SoundData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteFile(string file)
|
|
||||||
{
|
|
||||||
FileStream fs = File.Create(file);
|
|
||||||
|
|
||||||
//Set the total file chunk size
|
|
||||||
//Has to be set here because we might not know what the actual Data size was until now
|
|
||||||
header.SetChunkSize(fmt.Size, data.Size);
|
|
||||||
|
|
||||||
header.WriteHeader(fs);
|
|
||||||
fmt.Writefmt(fs);
|
|
||||||
data.WriteData(fs);
|
|
||||||
|
|
||||||
fs.Close();
|
|
||||||
fs.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int NumChannels { get { return fmt.NumChannels; }}
|
|
||||||
public int BitsPerSample { get { return fmt.BitsPerSample; }}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace WaveLibrary
|
|
||||||
{
|
|
||||||
class WaveHeader
|
|
||||||
{
|
|
||||||
string ChunkID = "RIFF";
|
|
||||||
int ChunkSize = 0;
|
|
||||||
string Format = "WAVE"; //Specifiy WAVE, AVI could also be used for a RIFF format
|
|
||||||
|
|
||||||
public WaveHeader()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
public void SetChunkSize(int fmtSubChunkSize, int dataSubChunkSize)
|
|
||||||
{
|
|
||||||
ChunkSize = 4 + (8 + fmtSubChunkSize) + (8 + dataSubChunkSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteHeader(FileStream fs)
|
|
||||||
{
|
|
||||||
//ChunkID
|
|
||||||
byte[] riff = Encoding.ASCII.GetBytes(ChunkID);
|
|
||||||
fs.Write(riff, 0, riff.Length);
|
|
||||||
|
|
||||||
//Chunk Size
|
|
||||||
byte[] chunkSize = BitConverter.GetBytes(ChunkSize);
|
|
||||||
fs.Write(chunkSize, 0, chunkSize.Length);
|
|
||||||
|
|
||||||
//Data Type
|
|
||||||
byte[] wave = Encoding.ASCII.GetBytes(Format);
|
|
||||||
fs.Write(wave, 0, wave.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Chunk_Size { get { return ChunkSize; }}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace WaveLibrary
|
|
||||||
{
|
|
||||||
class WavedataSubChunk
|
|
||||||
{
|
|
||||||
string SubChunk2ID = "data";
|
|
||||||
int SubChunk2Size;
|
|
||||||
byte[] SoundData;
|
|
||||||
|
|
||||||
public WavedataSubChunk(int NumSamples, int NumChannels, int BitsPerSample, byte[] SoundData)
|
|
||||||
{
|
|
||||||
SubChunk2Size = NumSamples * NumChannels * (BitsPerSample / 8);
|
|
||||||
this.SoundData = SoundData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteData(FileStream fs)
|
|
||||||
{
|
|
||||||
//Chunk ID
|
|
||||||
byte[] _subChunk2ID = Encoding.ASCII.GetBytes(SubChunk2ID);
|
|
||||||
fs.Write(_subChunk2ID, 0, _subChunk2ID.Length);
|
|
||||||
|
|
||||||
//Chunk Size
|
|
||||||
byte[] _subChunk2Size = BitConverter.GetBytes(SubChunk2Size);
|
|
||||||
fs.Write(_subChunk2Size, 0, _subChunk2Size.Length);
|
|
||||||
|
|
||||||
//Wave Sound Data
|
|
||||||
fs.Write(SoundData, 0, SoundData.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Size { get { return SubChunk2Size; } }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace WaveLibrary
|
|
||||||
{
|
|
||||||
class WavefmtSubChunk
|
|
||||||
{
|
|
||||||
string SubChunk1ID = "fmt ";
|
|
||||||
int Subchunk1Size = 16; //For PCM
|
|
||||||
int AudioFormat = 1; //For no compression
|
|
||||||
public int NumChannels = 2; //1 For Mono, 2 For Stereo
|
|
||||||
int SampleRate = 22050;
|
|
||||||
int ByteRate;
|
|
||||||
int BlockAlign;
|
|
||||||
public int BitsPerSample = 16;
|
|
||||||
|
|
||||||
public WavefmtSubChunk(int channels, int bitsPerSamples, int sampleRate)
|
|
||||||
{
|
|
||||||
BitsPerSample = bitsPerSamples;
|
|
||||||
NumChannels = channels;
|
|
||||||
SampleRate = sampleRate;
|
|
||||||
ByteRate = SampleRate * NumChannels * (BitsPerSample / 8);
|
|
||||||
BlockAlign = NumChannels * (BitsPerSample / 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Writefmt(FileStream fs)
|
|
||||||
{
|
|
||||||
//Chunk ID
|
|
||||||
byte[] _subchunk1ID = Encoding.ASCII.GetBytes(SubChunk1ID);
|
|
||||||
fs.Write(_subchunk1ID, 0, _subchunk1ID.Length);
|
|
||||||
|
|
||||||
//Chunk Size
|
|
||||||
byte[] _subchunk1Size = BitConverter.GetBytes(Subchunk1Size);
|
|
||||||
fs.Write(_subchunk1Size, 0, _subchunk1Size.Length);
|
|
||||||
|
|
||||||
//Audio Format (PCM)
|
|
||||||
byte[] _audioFormat = BitConverter.GetBytes(AudioFormat);
|
|
||||||
fs.Write(_audioFormat, 0, 2);
|
|
||||||
|
|
||||||
//Number of Channels (1 or 2)
|
|
||||||
byte[] _numChannels = BitConverter.GetBytes(NumChannels);
|
|
||||||
fs.Write(_numChannels, 0, 2);
|
|
||||||
|
|
||||||
//Sample Rate
|
|
||||||
byte[] _sampleRate = BitConverter.GetBytes(SampleRate);
|
|
||||||
fs.Write(_sampleRate, 0, _sampleRate.Length);
|
|
||||||
|
|
||||||
//Byte Rate
|
|
||||||
byte[] _byteRate = BitConverter.GetBytes(ByteRate);
|
|
||||||
fs.Write(_byteRate, 0, _byteRate.Length);
|
|
||||||
|
|
||||||
//Block Align
|
|
||||||
byte[] _blockAlign = BitConverter.GetBytes(BlockAlign);
|
|
||||||
fs.Write(_blockAlign, 0, 2);
|
|
||||||
|
|
||||||
//Bits Per Sample
|
|
||||||
byte[] _bitsPerSample = BitConverter.GetBytes(BitsPerSample);
|
|
||||||
fs.Write(_bitsPerSample, 0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Size { get { return Subchunk1Size; } }
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue