private Index lastTrackIndex(Track track) { return track.Indices[track.Indices.Length - 1]; }
/// <summary> /// Read MusicTag information from cueFakeTrack /// Not thread safe! /// </summary> /// <param name="cueFakeTrackFileName">Cue fake track file name</param> /// <returns>MusicTag filled with cue track information</returns> public static MusicTag CueFakeTrackFile2MusicTag(string cueFakeTrackFileName) { lock (cacheLock) { // This metod called twice for each one file. So, cache data! if (cueFakeTrackFileName == cueFakeTrackFileNameCache) { return(musicTagCache); } cueFakeTrackFileNameCache = cueFakeTrackFileName; // Cache CueSheet to pervent parsing it for each track in the album CueFakeTrack cueFakeTrack = parseCueFakeTrackFileName(cueFakeTrackFileName); if (cueSheetCacheFileNameCache != cueFakeTrack.CueFileName) { cueSheetCache = new CueSheet(cueFakeTrack.CueFileName); cueSheetCacheFileNameCache = cueFakeTrack.CueFileName; } int trackPosition = cueFakeTrack.TrackNumber - cueSheetCache.Tracks[0].TrackNumber; Track track = cueSheetCache.Tracks[trackPosition]; musicTagCache = new MusicTag(); if (track.TrackNumber < cueSheetCache.Tracks[cueSheetCache.Tracks.Length - 1].TrackNumber) { Track nextTrack = cueSheetCache.Tracks[trackPosition + 1]; musicTagCache.Duration = cueIndexToIntTime(nextTrack.Indices[0]) - cueIndexToIntTime(track.Indices[0]); } string fname = Path.Combine(Path.GetDirectoryName(cueFakeTrack.CueFileName), track.DataFile.Filename); try { if (fname != cacheFName) { tagCache = TagLib.File.Create(fname); } cacheFName = fname; musicTagCache.FileType = tagCache.MimeType; musicTagCache.Year = (int)tagCache.Tag.Year; musicTagCache.BitRate = tagCache.Properties.AudioBitrate; musicTagCache.DiscID = (int)tagCache.Tag.Disc; musicTagCache.DiscTotal = (int)tagCache.Tag.DiscCount; ; if (musicTagCache.Duration == 0) { musicTagCache.Duration = (int)tagCache.Properties.Duration.TotalSeconds - cueIndexToIntTime(track.Indices[0]); } } catch (Exception ex) { Log.Warn("CueFakeTrackFile2MusicTag: Exception reading file {0}. {1}", fname, ex.Message); } // In case of having a multi file Cue sheet, we're not able to get the duration // from the index entries. use MediaInfo then if (musicTagCache.Duration == 0) { try { MediaInfo mi = new MediaInfo(); mi.Open(fname); int durationms = 0; int.TryParse(mi.Get(StreamKind.General, 0, "Duration"), out durationms); musicTagCache.Duration = durationms / 1000; mi.Close(); } catch (Exception ex1) { Log.Warn("CueFakeTrackFile2MusicTag: Exception retrieving duration for file {0}. {1}", fname, ex1.Message); } } if (string.IsNullOrEmpty(musicTagCache.Artist)) { // if track has a performer set use this value for artist tag // else use global performer defined for cue sheet if (!string.IsNullOrEmpty(track.Performer)) { musicTagCache.Artist = track.Performer; } else { musicTagCache.Artist = cueSheetCache.Performer; } } if (string.IsNullOrEmpty(musicTagCache.Album)) { musicTagCache.Album = cueSheetCache.Title; } if (string.IsNullOrEmpty(musicTagCache.AlbumArtist)) { if (!string.IsNullOrEmpty(cueSheetCache.Performer)) { musicTagCache.AlbumArtist = cueSheetCache.Performer; musicTagCache.HasAlbumArtist = true; } else { musicTagCache.HasAlbumArtist = false; } } // let tagged genre override cuesheet genre if (string.IsNullOrEmpty(musicTagCache.Genre) && !string.IsNullOrEmpty(cueSheetCache.Genre)) { musicTagCache.Genre = cueSheetCache.Genre; } // let tagged year override cuesheet year if (musicTagCache.Year == 0 && cueSheetCache.Year != 0) { musicTagCache.Year = cueSheetCache.Year; } // let tagged composer override cuesheet songwriter if (string.IsNullOrEmpty(musicTagCache.Composer) && !string.IsNullOrEmpty(cueSheetCache.Songwriter)) { musicTagCache.Composer = cueSheetCache.Songwriter; } //musicTagCache.CoverArtImageBytes = pics[0].Data.Data; musicTagCache.FileName = cueFakeTrackFileName; musicTagCache.Title = track.Title; musicTagCache.Track = track.TrackNumber; musicTagCache.TrackTotal = cueSheetCache.Tracks.Length; return(musicTagCache); } }
/// <summary> /// Add a track to the current cuesheet /// </summary> /// <param name="track">Track object to add to the cuesheet.</param> public void AddTrack(Track track) { m_Tracks = (Track[])ResizeArray(m_Tracks, m_Tracks.Length + 1); m_Tracks[m_Tracks.Length - 1] = track; }
/// <summary> /// Read MusicTag information from cueFakeTrack /// Not thread safe! /// </summary> /// <param name="cueFakeTrackFileName">Cue fake track file name</param> /// <returns>MusicTag filled with cue track information</returns> public static MusicTag CueFakeTrackFile2MusicTag(string cueFakeTrackFileName) { lock (cacheLock) { // This metod called twice for each single file. So, cache data! if (cueFakeTrackFileName == cueFakeTrackFileNameCache) { return(musicTagCache); } cueFakeTrackFileNameCache = cueFakeTrackFileName; // Cache CueSheet to pervent parsing it for each track in the album CueFakeTrack cueFakeTrack = parseCueFakeTrackFileName(cueFakeTrackFileName); if (cueSheetCacheFileNameCache != cueFakeTrack.CueFileName) { cueSheetCache = new CueSheet(cueFakeTrack.CueFileName); cueSheetCacheFileNameCache = cueFakeTrack.CueFileName; } int trackPosition = cueFakeTrack.TrackNumber - cueSheetCache.Tracks[0].TrackNumber; Track track = cueSheetCache.Tracks[trackPosition]; musicTagCache = new MusicTag(); if (track.TrackNumber < cueSheetCache.Tracks[cueSheetCache.Tracks.Length - 1].TrackNumber) { Track nextTrack = cueSheetCache.Tracks[trackPosition + 1]; musicTagCache.Duration = cueIndexToIntTime(nextTrack.Indices[0]) - cueIndexToIntTime(track.Indices[0]); } string fname = Path.Combine(Path.GetDirectoryName(cueFakeTrack.CueFileName), track.DataFile.Filename); try { if (fname != cacheFName) { TagLib.File file = TagLib.File.Create(fname); tagCache = new TagCache(); tagCache.CopyTags(file); } cacheFName = fname; musicTagCache.FileType = tagCache.FileType; musicTagCache.Codec = tagCache.Codec; musicTagCache.Year = tagCache.Year; musicTagCache.BitRate = tagCache.BitRate; musicTagCache.DiscID = tagCache.DiscId; musicTagCache.DiscTotal = tagCache.DiscTotal; musicTagCache.Channels = tagCache.Channels; musicTagCache.SampleRate = tagCache.SampleRate; musicTagCache.BitRateMode = tagCache.BitRateMode; if (musicTagCache.Duration == 0) { musicTagCache.Duration = tagCache.Duration - cueIndexToIntTime(track.Indices[0]); } } catch (Exception ex) { Log.Error("CueUtil:CueFakeTrackFile2MusicTag {0}", ex.Message); // If we end up here this means that we were not able to read the file // Most probably because of taglib-sharp not supporting the audio file // For example DTS file format has no Tags, but can be replayed by BASS // Use MediaInfo to read the properties if (fname != cacheFName) { tagCache = new TagCache(); if (tagCache.CopyMediaInfo(fname)) { musicTagCache.FileType = tagCache.FileType; musicTagCache.Codec = tagCache.Codec; musicTagCache.BitRate = tagCache.BitRate; musicTagCache.Channels = tagCache.Channels; musicTagCache.SampleRate = tagCache.SampleRate; musicTagCache.BitRateMode = tagCache.BitRateMode; if (musicTagCache.Duration == 0) { musicTagCache.Duration = tagCache.Duration - cueIndexToIntTime(track.Indices[0]); } } } cacheFName = fname; } // In case of having a multi file Cue sheet, we're not able to get the duration // from the index entries. use MediaInfo then if (musicTagCache.Duration == 0) { try { var logger = GlobalServiceProvider.Get <MediaInfo.ILogger>(); var mi = new MediaInfoWrapper(fname, logger); if (!mi.MediaInfoNotloaded) { mi.WriteInfo(); musicTagCache.Duration = (int?)mi.BestAudioStream?.Duration.TotalSeconds ?? 0; } } catch (Exception ex1) { Log.Warn("CueFakeTrackFile2MusicTag: Exception retrieving duration for file {0}. {1}", fname, ex1.Message); } } if (string.IsNullOrEmpty(musicTagCache.Artist)) { // if track has a performer set use this value for artist tag // else use global performer defined for cue sheet if (!string.IsNullOrEmpty(track.Performer)) { musicTagCache.Artist = track.Performer; } else { musicTagCache.Artist = cueSheetCache.Performer; } } if (string.IsNullOrEmpty(musicTagCache.Album)) { musicTagCache.Album = cueSheetCache.Title; } if (string.IsNullOrEmpty(musicTagCache.AlbumArtist)) { if (!string.IsNullOrEmpty(cueSheetCache.Performer)) { musicTagCache.AlbumArtist = cueSheetCache.Performer; musicTagCache.HasAlbumArtist = true; } else { musicTagCache.HasAlbumArtist = false; } } // let tagged genre override cuesheet genre if (string.IsNullOrEmpty(musicTagCache.Genre) && !string.IsNullOrEmpty(cueSheetCache.Genre)) { musicTagCache.Genre = cueSheetCache.Genre; } // let tagged year override cuesheet year if (musicTagCache.Year == 0 && cueSheetCache.Year != 0) { musicTagCache.Year = cueSheetCache.Year; } // let tagged composer override cuesheet songwriter if (string.IsNullOrEmpty(musicTagCache.Composer) && !string.IsNullOrEmpty(cueSheetCache.Songwriter)) { musicTagCache.Composer = cueSheetCache.Songwriter; } // in case we were not able to read the file type via taglib, we will get it vai extension if (string.IsNullOrEmpty(musicTagCache.FileType)) { var extension = Path.GetExtension(fname); if (extension != null) { musicTagCache.FileType = extension.Substring(1).ToLowerInvariant(); } } musicTagCache.FileName = cueFakeTrackFileName; musicTagCache.Title = track.Title; musicTagCache.Track = track.TrackNumber; musicTagCache.TrackTotal = cueSheetCache.Tracks.Length; return(musicTagCache); } }