/// <summary> /// 単体の音楽ファイルを解析する /// </summary> /// <param name="file_name">ファイル名</param> /// <param name="threadLocalResultQueue">スレッド固有の解析結果</param> /// <param name="lastModifySTMT">modifyを取得するプリペアドステートメント</param> private void AnalyzeStreamFile(string file_name, List <LuteaAudioTrack> threadLocalResultQueue, SQLite3DB.STMT lastModifySTMT) { // 既に処理済みの場合はreturn if (AlreadyAnalyzedFiles.Contains(file_name)) { return; } // 処理済みファイルに追加 lock (AlreadyAnalyzedFiles) { AlreadyAnalyzedFiles.Add(file_name); } if (LastModifyDatetime(lastModifySTMT, file_name) > new System.IO.FileInfo(file_name).LastWriteTime&& IsFastMode) { return; } var tag = MetaTag.readTagByFilename(file_name, false); if (tag == null) { return; } var cue = tag.Find(match => match.Key.ToUpper() == "CUESHEET"); if (cue.Key != null) { var cd = InternalCUEReader.Read(file_name, true); if (cd == null) { Logger.Error("CUESHEET is embedded. But, it has error. " + file_name); return; } threadLocalResultQueue.AddRange(cd.tracks.Cast <LuteaAudioTrack>()); } else { // PERFORMERがないとき、ARTISTをPERFORMERとして扱う if (tag.Find((e) => { return(e.Key == "PERFORMER"); }).Value == null) { var artist = tag.Find((e) => { return(e.Key == "ARTIST"); }); if (artist.Value != null) { tag.Add(new KeyValuePair <string, object>("PERFORMER", artist.Value)); } } var tr = new LuteaAudioTrack() { file_name = file_name, file_size = new System.IO.FileInfo(file_name).Length }; if (tag.Exists(_ => _.Key == "__X-LUTEA-CHANS__") && tag.Exists(_ => _.Key == "__X-LUTEA-FREQ__") && tag.Exists(_ => _.Key == "__X-LUTEA-DURATION__")) { tr.duration = int.Parse(tag.Find(_ => _.Key == "__X-LUTEA-DURATION__").Value.ToString()); tr.channels = int.Parse(tag.Find(_ => _.Key == "__X-LUTEA-CHANS__").Value.ToString()); tr.freq = int.Parse(tag.Find(_ => _.Key == "__X-LUTEA-FREQ__").Value.ToString()); } else { try { using (var strm = DecodeStreamFactory.CreateFileStreamPrimitive(file_name)) { tr.duration = (int)strm.LengthSec; tr.channels = (int)strm.Chans; tr.freq = (int)strm.Freq; } } catch (ArgumentException ex) { Logger.Error("cannot open file (by BASS)" + file_name); Logger.Debug(ex); } } tr.tag = tag; if (tr.file_ext == "M4A") { if (tag.Exists(_ => (_.Key == "PURCHASE DATE") || (_.Key == "PURCHASED"))) { if ((TypesToImport & ImportableTypes.M4A_iTunes) == 0) { return; } } else if (tr.codec == H2k6Codec.ALAC) { if ((TypesToImport & ImportableTypes.M4A_ALAC) == 0) { return; } } else { if ((TypesToImport & ImportableTypes.M4A) == 0) { return; } } } threadLocalResultQueue.Add(tr); } }
public static CD Read(string filename, bool readStream) { var tag = MetaTag.readTagByFilename(filename, false); CD cd = CUEReader.ReadFromString(tag.Find((e) => e.Key == "CUESHEET").Value.ToString(), filename, readStream); if (cd == null) { return(null); } long bits = (new FileInfo(filename)).Length * 8; int bitrate = 1410 * 1000; try { using (var strm = new BASS.FileStream(filename, BASS.Stream.StreamFlag.BASS_STREAM_DECODE)) { bitrate = (int)(bits / strm.length); } } catch (Exception ex) { Logger.Error("cannot open file (by BASS)" + filename); Logger.Debug(ex); } foreach (var tr in cd.tracks) { // トラック番号取得 int trackindex = 0; var trackIndex = tr.tag.Find((match) => match.Key == "TRACK" ? true : false); trackindex = int.Parse(trackIndex.Value.ToString()); // その他、ディスク全体のタグ情報をまとめてぶっこむ foreach (var disctag in tag) { tr.tag.RemoveAll(_ => _.Key == disctag.Key); tr.tag.Add(disctag); } // InCUEの拡張タグ(?)をトラックのタグに付加 var customColumns = tag.FindAll((e) => e.Key.IndexOf(string.Format("CUE_TRACK{0:00}_", trackindex)) == 0); foreach (var col in customColumns) { string key = new Regex(@"^CUE_TRACK\d\d_(?<1>.*)$").Match(col.Key).Groups[1].Value; tr.tag.RemoveAll(_ => _.Key == key); tr.tag.Insert(0, new KeyValuePair <string, object>(key, col.Value)); } // PERFORMERがないとき、ARTISTをPERFORMERとして扱う if (tr.tag.Find((e) => { return(e.Key == "PERFORMER"); }).Value == null) { var artist = tr.tag.Find((e) => { return(e.Key == "ARTIST"); }); if (artist.Value != null) { tr.tag.Add(new KeyValuePair <string, object>("PERFORMER", artist.Value)); } } // InCUE内のFILE名が実体と異なっている場合があるため、ビットレートを付加しなおす tr.bitrate = bitrate; } return(cd); }
/// <summary> /// CUEシートを解析する /// </summary> /// <param name="file_name">ファイル名</param> /// <param name="lastModifySTMT">modifyを取得するプリペアドステートメント</param> private void AnalyzeCUE(string file_name, List <LuteaAudioTrack> threadLocalResults, SQLite3DB.STMT lastModifySTMT) { // 既に処理済みの場合はreturn if (AlreadyAnalyzedFiles.Contains(file_name)) { return; } // 処理済みファイルに追加 lock (AlreadyAnalyzedFiles) { AlreadyAnalyzedFiles.Add(file_name); } // ファイルを解析 var cd = CUEReader.ReadFromFile(file_name, true); if (cd == null) { return; } string lastCheckedFilename = null; bool lastCheckedFileShouldSkip = false; bool modifyed = LastModifyDatetime(lastModifySTMT, file_name) <= new System.IO.FileInfo(file_name).LastWriteTime; foreach (CD.Track tr in cd.tracks) { if (tr.file_name_CUESheet == "") { continue; } // 実体ストリームが存在しない、またはCUESHEETが埋め込まれているなら、.cueファイルとしてのインポートはスキップする。 if (lastCheckedFilename != tr.file_name_CUESheet) { lastCheckedFilename = tr.file_name_CUESheet; lastCheckedFileShouldSkip = false; if (!System.IO.File.Exists(tr.file_name_CUESheet)) { lastCheckedFileShouldSkip = true; } // CUEシートが埋め込まれているならスキップ var tagInRealStream = MetaTag.readTagByFilename(tr.file_name_CUESheet, false); if (tagInRealStream != null && (tagInRealStream.Exists(e => e.Key == "CUESHEET"))) { lastCheckedFileShouldSkip = true; } } // ストリームのタグにCUESHEETがある時はなにもしない if (lastCheckedFileShouldSkip) { continue; } lock (AlreadyAnalyzedFiles) { AlreadyAnalyzedFiles.AddRange(cd.tracks.Select(_ => _.file_name_CUESheet)); } if (modifyed || !IsFastMode) { threadLocalResults.Add(tr); } } }