diff --git a/APEDotNet/apedotnet.cpp b/APEDotNet/apedotnet.cpp index 46770f2..c5eee73 100644 --- a/APEDotNet/apedotnet.cpp +++ b/APEDotNet/apedotnet.cpp @@ -128,7 +128,12 @@ namespace APEDotNet { property NameValueCollection^ Tags { 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; } void set (NameValueCollection ^tags) { diff --git a/APETagDotNet/APETagDotNet.cs b/APETagDotNet/APETagDotNet.cs index 8d89619..4af8729 100644 --- a/APETagDotNet/APETagDotNet.cs +++ b/APETagDotNet/APETagDotNet.cs @@ -114,9 +114,9 @@ namespace APETagsDotNet { LittleEndian.Write32(pBuffer, pos, _fieldValue.Length); 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; - Array.Copy(_fieldValue, pBuffer, pos + 8 + _fieldName.Length + 1); + Array.Copy(_fieldValue, 0, pBuffer, pos + 8 + _fieldName.Length + 1, _fieldValue.Length); return GetFieldSize(); } @@ -173,26 +173,33 @@ namespace APETagsDotNet // create an APE tags object // 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 - 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_aryFields = new APETagField[0]; m_nTagBytes = 0; m_bIgnoreReadOnly = false; if (analyze) Analyze (); } + + public void Close () + { + m_spIO.Close (); + ClearFields (); + } // 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) - int Save () + public bool Save () { if (!Remove(false)) - return -1; + return false; - if (m_aryFields.Length == 0) { return 0; } + if (m_aryFields.Length == 0) + return true; int z = 0; @@ -221,7 +228,7 @@ namespace APETagsDotNet // dump the tag to the I/O source WriteBufferToEndOfIO (spRawTag); - return 0; + return true; } // 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) // 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 if (fieldValue == "") @@ -390,6 +397,22 @@ namespace APETagsDotNet 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 void RemoveField(string pFieldName) diff --git a/CUETools/AudioReadWrite.cs b/CUETools/AudioReadWrite.cs index dd7eeae..a7f3572 100644 --- a/CUETools/AudioReadWrite.cs +++ b/CUETools/AudioReadWrite.cs @@ -21,6 +21,7 @@ namespace JDP { public interface IAudioDest { void Write(byte[] buff, uint sampleCount); + bool SetTags(NameValueCollection tags); void Close(); long FinalSampleCount { set; } } @@ -65,6 +66,10 @@ namespace JDP { public DummyWriter (string path, int bitsPerSample, int channelCount, int sampleRate) { } + public bool SetTags(NameValueCollection tags) + { + return false; + } public void Close() { } @@ -292,6 +297,11 @@ namespace JDP { WriteHeaders(); } + public bool SetTags(NameValueCollection tags) + { + return false; + } + private void WriteHeaders() { const uint fccRIFF = 0x46464952; const uint fccWAVE = 0x45564157; @@ -535,9 +545,10 @@ namespace JDP { } } - public void SetTags(NameValueCollection tags) + public bool SetTags(NameValueCollection tags) { _flacWriter.SetTags (tags); + return true; } public void Close() { @@ -809,6 +820,12 @@ namespace JDP { _wavPackWriter = new WavPackDotNet.WavPackWriter(path, bitsPerSample, channelCount, sampleRate); } + public bool SetTags(NameValueCollection tags) + { + _wavPackWriter.SetTags(tags); + return true; + } + public long FinalSampleCount { get { return _wavPackWriter.FinalSampleCount; diff --git a/CUETools/Main.cs b/CUETools/Main.cs index 0448dc7..16173ff 100644 --- a/CUETools/Main.cs +++ b/CUETools/Main.cs @@ -945,7 +945,7 @@ namespace JDP { uint timeRelativeToFileStart = 0; using (sw) { - if (_accurateRipId != null) + if (_accurateRipId != null && _config.writeArTags) WriteLine(sw, 0, "REM ACCURATERIPID " + _accurateRipId); @@ -1602,9 +1602,8 @@ namespace JDP { { iDest++; 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(); if (_hasEmbeddedCUESheet || _hasSingleFilename) @@ -1649,7 +1648,7 @@ namespace JDP { else destTags.Add("ACCURATERIPID", _accurateRipId); } - w.SetTags(destTags); + audioDest.SetTags(destTags); } } diff --git a/CUETools/frmCUETools.cs b/CUETools/frmCUETools.cs index 2779d6b..061eb2d 100644 --- a/CUETools/frmCUETools.cs +++ b/CUETools/frmCUETools.cs @@ -803,8 +803,8 @@ namespace JDP { private void updateOutputStyles() { - rbEmbedCUE.Enabled = rbFLAC.Checked; - rbNoAudio.Enabled = rbWAV.Enabled = rbWavPack.Enabled = !rbEmbedCUE.Checked; + rbEmbedCUE.Enabled = rbFLAC.Checked || rbWavPack.Checked; + rbNoAudio.Enabled = rbWAV.Enabled = !rbEmbedCUE.Checked; } private void rbWAV_CheckedChanged(object sender, EventArgs e) diff --git a/WavPackDotNet/WavPackDotNet.cpp b/WavPackDotNet/WavPackDotNet.cpp index 8d919a7..e9a3d72 100644 --- a/WavPackDotNet/WavPackDotNet.cpp +++ b/WavPackDotNet/WavPackDotNet.cpp @@ -116,7 +116,12 @@ namespace WavPackDotNet { property NameValueCollection^ Tags { 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; } void set (NameValueCollection ^tags) { @@ -157,6 +162,9 @@ namespace WavPackDotNet { throw gcnew Exception("Only stereo and mono audio formats are allowed."); } + _path = path; + _tags = gcnew NameValueCollection(); + _compressionMode = 1; _extraMode = 0; @@ -180,6 +188,15 @@ namespace WavPackDotNet { if ((_finalSampleCount != 0) && (_samplesWritten != _finalSampleCount)) { 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 { @@ -233,6 +250,10 @@ namespace WavPackDotNet { _samplesWritten += sampleCount; } + void SetTags (NameValueCollection^ tags) { + _tags = tags; + } + private: FILE *_hFile; bool _initialized; @@ -240,6 +261,8 @@ namespace WavPackDotNet { Int32 _finalSampleCount, _samplesWritten; Int32 _bitsPerSample, _channelCount, _sampleRate; Int32 _compressionMode, _extraMode; + NameValueCollection^ _tags; + String^ _path; void Initialize() { WavpackConfig config; diff --git a/flac/src/libFLAC/ia32/bitreader_asm.obj b/flac/src/libFLAC/ia32/bitreader_asm.obj index cdcef89..82714b9 100644 Binary files a/flac/src/libFLAC/ia32/bitreader_asm.obj and b/flac/src/libFLAC/ia32/bitreader_asm.obj differ