Wavpack output can now have tags and embedded cue sheet.

This commit is contained in:
chudov
2008-10-15 02:25:21 +00:00
parent e342ad80c2
commit ab94a4f25e
7 changed files with 86 additions and 19 deletions

View File

@@ -128,7 +128,12 @@ namespace APEDotNet {
property NameValueCollection^ Tags { property NameValueCollection^ Tags {
NameValueCollection^ get () { NameValueCollection^ get () {
if (!_tags) _tags = (gcnew APETagDotNet (_path, true))->GetStringTags (true); if (!_tags)
{
APETagDotNet^ apeTag = gcnew APETagDotNet (_path, true, true);
_tags = apeTag->GetStringTags (true);
apeTag->Close ();
}
return _tags; return _tags;
} }
void set (NameValueCollection ^tags) { void set (NameValueCollection ^tags) {

View File

@@ -114,9 +114,9 @@ namespace APETagsDotNet
{ {
LittleEndian.Write32(pBuffer, pos, _fieldValue.Length); LittleEndian.Write32(pBuffer, pos, _fieldValue.Length);
LittleEndian.Write32(pBuffer, pos + 4, _fieldFlags); LittleEndian.Write32(pBuffer, pos + 4, _fieldFlags);
Array.Copy (new ASCIIEncoding().GetBytes(_fieldName), pBuffer, pos + 8); Array.Copy(new ASCIIEncoding().GetBytes(_fieldName), 0, pBuffer, pos + 8, _fieldName.Length);
pBuffer[pos + 8 + _fieldName.Length] = 0; pBuffer[pos + 8 + _fieldName.Length] = 0;
Array.Copy(_fieldValue, pBuffer, pos + 8 + _fieldName.Length + 1); Array.Copy(_fieldValue, 0, pBuffer, pos + 8 + _fieldName.Length + 1, _fieldValue.Length);
return GetFieldSize(); return GetFieldSize();
} }
@@ -173,9 +173,9 @@ namespace APETagsDotNet
// create an APE tags object // create an APE tags object
// bAnalyze determines whether it will analyze immediately or on the first request // bAnalyze determines whether it will analyze immediately or on the first request
// be careful with multiple threads / file pointer movement if you don't analyze immediately // be careful with multiple threads / file pointer movement if you don't analyze immediately
public APETagDotNet (string filename, bool analyze) public APETagDotNet (string filename, bool analyze, bool isReadonly)
{ {
m_spIO = new FileStream (filename, FileMode.Open, FileAccess.Read, FileShare.Read); m_spIO = new FileStream(filename, FileMode.Open, isReadonly?FileAccess.Read:FileAccess.ReadWrite, FileShare.Read);
m_bAnalyzed = false; m_bAnalyzed = false;
m_aryFields = new APETagField[0]; m_aryFields = new APETagField[0];
m_nTagBytes = 0; m_nTagBytes = 0;
@@ -183,16 +183,23 @@ namespace APETagsDotNet
if (analyze) Analyze (); if (analyze) Analyze ();
} }
public void Close ()
{
m_spIO.Close ();
ClearFields ();
}
// destructor // destructor
~APETagDotNet () { ClearFields (); } ~APETagDotNet () { }
// save the tag to the I/O source (bUseOldID3 forces it to save as an ID3v1.1 tag instead of an APE tag) // save the tag to the I/O source (bUseOldID3 forces it to save as an ID3v1.1 tag instead of an APE tag)
int Save () public bool Save ()
{ {
if (!Remove(false)) if (!Remove(false))
return -1; return false;
if (m_aryFields.Length == 0) { return 0; } if (m_aryFields.Length == 0)
return true;
int z = 0; int z = 0;
@@ -221,7 +228,7 @@ namespace APETagsDotNet
// dump the tag to the I/O source // dump the tag to the I/O source
WriteBufferToEndOfIO (spRawTag); WriteBufferToEndOfIO (spRawTag);
return 0; return true;
} }
// removes any tags from the file (bUpdate determines whether is should re-analyze after removing the tag) // removes any tags from the file (bUpdate determines whether is should re-analyze after removing the tag)
@@ -294,7 +301,7 @@ namespace APETagsDotNet
// sets the value of a field (use nFieldBytes = -1 for null terminated strings) // sets the value of a field (use nFieldBytes = -1 for null terminated strings)
// note: using NULL or "" for a string type will remove the field // note: using NULL or "" for a string type will remove the field
void SetFieldString(string fieldName, string fieldValue) public void SetFieldString(string fieldName, string fieldValue)
{ {
// remove if empty // remove if empty
if (fieldValue == "") if (fieldValue == "")
@@ -390,6 +397,22 @@ namespace APETagsDotNet
return tags; return tags;
} }
public void SetStringTags(NameValueCollection tags, bool mapFromFlac)
{
for (int i = 0; i < tags.Count; i++)
{
String [] tagValues = tags.GetValues(i);
String tagName = tags.GetKey (i);
if (mapFromFlac)
{
if (tagName.ToUpper() == "DATE")
tagName = "YEAR";
if (tagName.ToUpper() == "TRACKNUMBER")
tagName = "TRACK";
}
SetFieldString(tagName, tagValues[0]);
}
}
// remove a specific field // remove a specific field
void RemoveField(string pFieldName) void RemoveField(string pFieldName)

View File

@@ -21,6 +21,7 @@ namespace JDP {
public interface IAudioDest { public interface IAudioDest {
void Write(byte[] buff, uint sampleCount); void Write(byte[] buff, uint sampleCount);
bool SetTags(NameValueCollection tags);
void Close(); void Close();
long FinalSampleCount { set; } long FinalSampleCount { set; }
} }
@@ -65,6 +66,10 @@ namespace JDP {
public DummyWriter (string path, int bitsPerSample, int channelCount, int sampleRate) { public DummyWriter (string path, int bitsPerSample, int channelCount, int sampleRate) {
} }
public bool SetTags(NameValueCollection tags)
{
return false;
}
public void Close() { public void Close() {
} }
@@ -292,6 +297,11 @@ namespace JDP {
WriteHeaders(); WriteHeaders();
} }
public bool SetTags(NameValueCollection tags)
{
return false;
}
private void WriteHeaders() { private void WriteHeaders() {
const uint fccRIFF = 0x46464952; const uint fccRIFF = 0x46464952;
const uint fccWAVE = 0x45564157; const uint fccWAVE = 0x45564157;
@@ -535,9 +545,10 @@ namespace JDP {
} }
} }
public void SetTags(NameValueCollection tags) public bool SetTags(NameValueCollection tags)
{ {
_flacWriter.SetTags (tags); _flacWriter.SetTags (tags);
return true;
} }
public void Close() { public void Close() {
@@ -809,6 +820,12 @@ namespace JDP {
_wavPackWriter = new WavPackDotNet.WavPackWriter(path, bitsPerSample, channelCount, sampleRate); _wavPackWriter = new WavPackDotNet.WavPackWriter(path, bitsPerSample, channelCount, sampleRate);
} }
public bool SetTags(NameValueCollection tags)
{
_wavPackWriter.SetTags(tags);
return true;
}
public long FinalSampleCount { public long FinalSampleCount {
get { get {
return _wavPackWriter.FinalSampleCount; return _wavPackWriter.FinalSampleCount;

View File

@@ -945,7 +945,7 @@ namespace JDP {
uint timeRelativeToFileStart = 0; uint timeRelativeToFileStart = 0;
using (sw) { using (sw) {
if (_accurateRipId != null) if (_accurateRipId != null && _config.writeArTags)
WriteLine(sw, 0, "REM ACCURATERIPID " + WriteLine(sw, 0, "REM ACCURATERIPID " +
_accurateRipId); _accurateRipId);
@@ -1602,9 +1602,8 @@ namespace JDP {
{ {
iDest++; iDest++;
audioDest = GetAudioDest(destPaths[iDest], destLengths[iDest], noOutput); audioDest = GetAudioDest(destPaths[iDest], destLengths[iDest], noOutput);
if (audioDest is FLACWriter) if (audioDest is FLACWriter || audioDest is WavPackWriter)
{ {
FLACWriter w = (FLACWriter)audioDest;
NameValueCollection destTags = new NameValueCollection(); NameValueCollection destTags = new NameValueCollection();
if (_hasEmbeddedCUESheet || _hasSingleFilename) if (_hasEmbeddedCUESheet || _hasSingleFilename)
@@ -1649,7 +1648,7 @@ namespace JDP {
else else
destTags.Add("ACCURATERIPID", _accurateRipId); destTags.Add("ACCURATERIPID", _accurateRipId);
} }
w.SetTags(destTags); audioDest.SetTags(destTags);
} }
} }

View File

@@ -803,8 +803,8 @@ namespace JDP {
private void updateOutputStyles() private void updateOutputStyles()
{ {
rbEmbedCUE.Enabled = rbFLAC.Checked; rbEmbedCUE.Enabled = rbFLAC.Checked || rbWavPack.Checked;
rbNoAudio.Enabled = rbWAV.Enabled = rbWavPack.Enabled = !rbEmbedCUE.Checked; rbNoAudio.Enabled = rbWAV.Enabled = !rbEmbedCUE.Checked;
} }
private void rbWAV_CheckedChanged(object sender, EventArgs e) private void rbWAV_CheckedChanged(object sender, EventArgs e)

View File

@@ -116,7 +116,12 @@ namespace WavPackDotNet {
property NameValueCollection^ Tags { property NameValueCollection^ Tags {
NameValueCollection^ get () { NameValueCollection^ get () {
if (!_tags) _tags = (gcnew APETagDotNet (_path, true))->GetStringTags (true); if (!_tags)
{
APETagDotNet^ apeTag = gcnew APETagDotNet (_path, true, true);
_tags = apeTag->GetStringTags (true);
apeTag->Close ();
}
return _tags; return _tags;
} }
void set (NameValueCollection ^tags) { void set (NameValueCollection ^tags) {
@@ -157,6 +162,9 @@ namespace WavPackDotNet {
throw gcnew Exception("Only stereo and mono audio formats are allowed."); throw gcnew Exception("Only stereo and mono audio formats are allowed.");
} }
_path = path;
_tags = gcnew NameValueCollection();
_compressionMode = 1; _compressionMode = 1;
_extraMode = 0; _extraMode = 0;
@@ -180,6 +188,15 @@ namespace WavPackDotNet {
if ((_finalSampleCount != 0) && (_samplesWritten != _finalSampleCount)) { if ((_finalSampleCount != 0) && (_samplesWritten != _finalSampleCount)) {
throw gcnew Exception("Samples written differs from the expected sample count."); throw gcnew Exception("Samples written differs from the expected sample count.");
} }
if (_tags->Count > 0)
{
APETagDotNet^ apeTag = gcnew APETagDotNet (_path, true, false);
apeTag->SetStringTags (_tags, true);
apeTag->Save();
apeTag->Close();
_tags->Clear ();
}
} }
property Int32 FinalSampleCount { property Int32 FinalSampleCount {
@@ -233,6 +250,10 @@ namespace WavPackDotNet {
_samplesWritten += sampleCount; _samplesWritten += sampleCount;
} }
void SetTags (NameValueCollection^ tags) {
_tags = tags;
}
private: private:
FILE *_hFile; FILE *_hFile;
bool _initialized; bool _initialized;
@@ -240,6 +261,8 @@ namespace WavPackDotNet {
Int32 _finalSampleCount, _samplesWritten; Int32 _finalSampleCount, _samplesWritten;
Int32 _bitsPerSample, _channelCount, _sampleRate; Int32 _bitsPerSample, _channelCount, _sampleRate;
Int32 _compressionMode, _extraMode; Int32 _compressionMode, _extraMode;
NameValueCollection^ _tags;
String^ _path;
void Initialize() { void Initialize() {
WavpackConfig config; WavpackConfig config;