public void RemoveIndex(int indexIndex) { for (int i = indexIndex; i < m_Indices.Length - 1; i++) { m_Indices[i] = m_Indices[i + 1]; } m_Indices = (Index[])CueSheet.ResizeArray(m_Indices, m_Indices.Length - 1); }
public void AddComment(string comment) { if (comment.Trim() != "") { m_Comments = (string[])CueSheet.ResizeArray(m_Comments, m_Comments.Length + 1); m_Comments[m_Comments.Length - 1] = comment; } }
public void AddGarbage(string garbage) { if (garbage.Trim() != "") { m_Garbage = (string[])CueSheet.ResizeArray(m_Garbage, m_Garbage.Length + 1); m_Garbage[m_Garbage.Length - 1] = garbage; } }
public void AddFlag(Flags flag) { //if it's not a none tag //and if the tags hasn't already been added if (flag != Flags.NONE && NewFlag(flag) == true) { m_TrackFlags = (Flags[])CueSheet.ResizeArray(m_TrackFlags, m_TrackFlags.Length + 1); m_TrackFlags[m_TrackFlags.Length - 1] = flag; } }
/// <summary> /// Cue file filter. Parse Cue sheet file, /// add cue fake track files for each one cue track, /// removes original single file ape flac wav and etc, from list /// </summary> /// <typeparam name="T">Type of obgects in fileList</typeparam> /// <param name="fileList">File list to be filtered</param> /// <param name="adaptor"></param> /// <returns></returns> public static IList <T> CUEFileListFilter <T>(IList <T> fileList, ICueTrackFileBuilder <T> builder) { if (fileList == null || fileList.Count == 0) { return(fileList); } List <string> exclusionList = new List <string>(2); List <T> resultList = new List <T>(fileList.Count); foreach (T fobj in fileList) { string fileName = builder.getFileName(fobj); if (CueUtil.isCueFile(fileName)) { exclusionList.Add(fileName); CueSheet cueSheet = new CueSheet(fileName); string cuePath = System.IO.Path.GetDirectoryName(fileName); foreach (Track track in cueSheet.Tracks) { if (!exclusionList.Contains(cuePath + "\\" + track.DataFile.Filename)) { exclusionList.Add(cuePath + "\\" + track.DataFile.Filename); } resultList.Add(builder.build(fileName, cueSheet, track)); } } else { if (!isWavCueFile(fileName)) { resultList.Add(fobj); } } } if (exclusionList.Count > 0) { List <T> tmpList = new List <T>(resultList.Count); foreach (T fobj in resultList) { if (!exclusionList.Contains(builder.getFileName(fobj))) { tmpList.Add(fobj); } } resultList = tmpList; } return(resultList); }
public GUIListItem build(string cueFileName, CueSheet cueSheet, Track track) { GUIListItem res = new GUIListItem(); res.IsFolder = false; res.Path = CueUtil.buildCueFakeTrackFileName(cueFileName, track); MediaPortal.Util.Utils.SetDefaultIcons(res); if (track.Performer != null && track.Performer != cueSheet.Performer) { res.Label = track.Performer + " - " + track.Title; } else { res.Label = track.Title; } res.Label = track.TrackNumber.ToString("00") + " " + res.Label; return(res); }
/// <summary> /// Parse the Cue file. Return a Fake Cue track and adjest the playback position within the file. /// </summary> /// <param name="filePath"></param> /// <returns></returns> private bool HandleCueFile(ref string filePath, bool endOnly) { try { _cueTrackStartPos = 0; _cueTrackEndPos = 0; if (CueUtil.isCueFakeTrackFile(filePath)) { Log.Debug("BASS: Playing CUE Track: {0}", filePath); _currentCueFakeTrackFileName = filePath; CueFakeTrack cueFakeTrack = CueUtil.parseCueFakeTrackFileName(filePath); if (!cueFakeTrack.CueFileName.Equals(_currentCueFileName)) { // New CUE. Update chached cue. _currentCueSheet = new CueSheet(cueFakeTrack.CueFileName); _currentCueFileName = cueFakeTrack.CueFileName; } // Get track start position Track track = _currentCueSheet.Tracks[cueFakeTrack.TrackNumber - _currentCueSheet.Tracks[0].TrackNumber]; Index index = track.Indices[0]; _cueTrackStartPos = CueUtil.cueIndexToFloatTime(index); // If single audio file and is not last track, set track end position. if (_currentCueSheet.Tracks[_currentCueSheet.Tracks.Length - 1].TrackNumber > track.TrackNumber) { Track nextTrack = _currentCueSheet.Tracks[cueFakeTrack.TrackNumber - _currentCueSheet.Tracks[0].TrackNumber + 1]; if (nextTrack.DataFile.Filename.Equals(track.DataFile.Filename)) { Index nindex = nextTrack.Indices[0]; _cueTrackEndPos = CueUtil.cueIndexToFloatTime(nindex); } } // If audio file is not changed, just set new start/end position and reset pause string audioFilePath = System.IO.Path.GetDirectoryName(cueFakeTrack.CueFileName) + System.IO.Path.DirectorySeparatorChar + track.DataFile.Filename; if (audioFilePath.CompareTo(_filePath) == 0 /* && StreamIsPlaying(stream)*/) { SetCueTrackEndPosition(GetCurrentStream(), endOnly); return true; } filePath = audioFilePath; } else { _currentCueFileName = null; _currentCueSheet = null; } } catch (System.IO.FileNotFoundException) { // The CUE File may have been moved Log.Error("BASS: Cue File cannot be found at the expected location. aborting playback."); } return false; }
/// <summary> /// Scan the folders in the selected shares for music files to be added to the database /// </summary> private void AddUpdateFiles() { DatabaseReorgEventArgs MyArgs = new DatabaseReorgEventArgs(); string strSQL; _processCount = 0; _songsAdded = 0; _songsUpdated = 0; _songsSkipped = 0; int allFilesCount = 0; foreach (string Share in _shares) { //dummy call to stop lots of watchers being created unnecessarily Util.Utils.FileExistsInCache(Path.Combine(Share, "folder.jpg")); // Get all the files for the given Share / Path try { foreach (FileInformation file in GetFilesRecursive(new DirectoryInfo(Share))) { allFilesCount++; if (allFilesCount % 1000 == 0) { Log.Info("MusicDBReorg: Procesing file {0}", allFilesCount); } MyArgs.progress = 4; MyArgs.phase = String.Format("Processing file {0}", allFilesCount); OnDatabaseReorgChanged(MyArgs); if (!CheckFileForInclusion(file)) { continue; } _processCount++; AddUpdateSong(file.Name); } } catch (Exception ex) { Log.Error("MusicDBReorg: Exception accessing file or folder: {0}", ex.Message); } } // Now we will remove the CUE data file from the database, since we will add Fake Tracks in the next step foreach (string cueFile in cueFiles) { try { CueSheet cueSheet = new CueSheet(cueFile); string cuePath = Path.GetDirectoryName(cueFile); string cueDataFile = cuePath + "\\" + cueSheet.Tracks[0].DataFile.Filename; DatabaseUtility.RemoveInvalidChars(ref cueDataFile); strSQL = String.Format("delete from tracks where strPath='{0}'", cueDataFile); try { DirectExecute(strSQL); } catch (Exception ex) { Log.Error("Error deleting song from Database: {0}", ex.Message); } } catch (Exception ex) { Log.Error("Exception Processing CUE File: {0}: {1}", cueFile, ex.Message); } } try { // Apply CUE Filter List<string> cueFileFakeTracks = new List<string>(); cueFileFakeTracks = (List<string>)CueUtil.CUEFileListFilterList<string>(cueFiles, CueUtil.CUE_TRACK_FILE_STRING_BUILDER); // and add them also to the Hashtable, so that they don't get deleted in the next step foreach (string song in cueFileFakeTracks) { _processCount++; AddUpdateSong(song); allFiles.Add(song, false); } } catch (Exception ex) { Log.Error("Error processing CUE files: {0}", ex.Message); } _resetEvent.Set(); }
/// <summary> /// Starts Playback of the given file /// </summary> /// <param name="filePath"></param> /// <returns></returns> public override bool Play(string filePath) { if (!_Initialized) { return false; } int stream = GetCurrentStream(); bool doFade = false; bool result = true; Speed = 1; // Set playback Speed to normal speed try { if (filePath.ToLower().CompareTo(FilePath.ToLower()) == 0 && stream != 0) { // Selected file is equal to current stream if (_State == PlayState.Paused) { // Resume paused stream if (_SoftStop) { Bass.BASS_ChannelSlideAttribute(stream, BASSAttribute.BASS_ATTRIB_VOL, 1, 500); } else { Bass.BASS_ChannelSetAttribute(stream, BASSAttribute.BASS_ATTRIB_VOL, 1); } result = Bass.BASS_Start(); if (_useASIO) { result = BassAsio.BASS_ASIO_Start(0); } if (result) { _State = PlayState.Playing; if (PlaybackStateChanged != null) { PlaybackStateChanged(this, PlayState.Paused, _State); } } return result; } } else { // Cue support cueTrackStartPos = 0; cueTrackEndPos = 0; if (CueUtil.isCueFakeTrackFile(filePath)) { Log.Debug("BASS: Playing CUE Track: {0}", filePath); currentCueFakeTrackFileName = filePath; CueFakeTrack cueFakeTrack = CueUtil.parseCueFakeTrackFileName(filePath); if (!cueFakeTrack.CueFileName.Equals(currentCueFileName)) { // New CUE. Update chached cue. currentCueSheet = new CueSheet(cueFakeTrack.CueFileName); currentCueFileName = cueFakeTrack.CueFileName; } // Get track start position Track track = currentCueSheet.Tracks[cueFakeTrack.TrackNumber - currentCueSheet.Tracks[0].TrackNumber]; Index index = track.Indices[0]; cueTrackStartPos = CueUtil.cueIndexToFloatTime(index); // If single audio file and is not last track, set track end position. if (currentCueSheet.Tracks[currentCueSheet.Tracks.Length - 1].TrackNumber > track.TrackNumber) { Track nextTrack = currentCueSheet.Tracks[cueFakeTrack.TrackNumber - currentCueSheet.Tracks[0].TrackNumber + 1]; if (nextTrack.DataFile.Filename.Equals(track.DataFile.Filename)) { Index nindex = nextTrack.Indices[0]; cueTrackEndPos = CueUtil.cueIndexToFloatTime(nindex); } } // If audio file is not changed, just set new start/end position and reset pause string audioFilePath = System.IO.Path.GetDirectoryName(cueFakeTrack.CueFileName) + System.IO.Path.DirectorySeparatorChar + track.DataFile.Filename; if (audioFilePath.CompareTo(FilePath) == 0 /* && StreamIsPlaying(stream)*/) { setCueTrackEndPosition(stream); return true; } filePath = audioFilePath; } else { currentCueFileName = null; currentCueSheet = null; } } if (stream != 0 && StreamIsPlaying(stream)) { int oldStream = stream; double oldStreamDuration = GetTotalStreamSeconds(oldStream); double oldStreamElapsedSeconds = GetStreamElapsedTime(oldStream); double crossFadeSeconds = (double)_CrossFadeIntervalMS; if (crossFadeSeconds > 0) crossFadeSeconds = crossFadeSeconds / 1000.0; if ((oldStreamDuration - (oldStreamElapsedSeconds + crossFadeSeconds) > -1)) { FadeOutStop(oldStream); } else { Bass.BASS_ChannelStop(oldStream); } doFade = true; stream = GetNextStream(); if (stream != 0 || StreamIsPlaying(stream)) { FreeStream(stream); } } if (stream != 0) { if (!Stopped) // Check if stopped already to avoid that Stop() is called two or three times { Stop(); } FreeStream(stream); } _State = PlayState.Init; // Make sure Bass is ready to begin playing again Bass.BASS_Start(); float crossOverSeconds = 0; if (_CrossFadeIntervalMS > 0) { crossOverSeconds = (float)_CrossFadeIntervalMS / 1000f; } if (filePath != string.Empty) { // Turn on parsing of ASX files Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_NET_PLAYLIST, 2); // We need different flags for standard BASS and ASIO / Mixing BASSFlag streamFlags; if (_useASIO || _Mixing) { streamFlags = BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT; // Don't use the BASS_STREAM_AUTOFREE flag on a decoding channel. will produce a BASS_ERROR_NOTAVAIL } else { streamFlags = BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_AUTOFREE; } FilePath = filePath; // create the stream _isCDDAFile = false; _isRadio = false; _isLastFMRadio = false; if (Util.Utils.IsCDDA(filePath)) { _isCDDAFile = true; // StreamCreateFile causes problems with Multisession disks, so use StreamCreate with driveindex and track index int driveindex = _cdDriveLetters.IndexOf(filePath.Substring(0, 1)); int tracknum = Convert.ToInt16(filePath.Substring(filePath.IndexOf(".cda") - 2, 2)); stream = BassCd.BASS_CD_StreamCreate(driveindex, tracknum - 1, streamFlags); if (stream == 0) Log.Error("BASS: CD: {0}.", Enum.GetName(typeof (BASSError), Bass.BASS_ErrorGetCode())); } else if (filePath.ToLower().Contains(@"http://") || filePath.ToLower().Contains(@"https://") || filePath.ToLower().StartsWith("mms") || filePath.ToLower().StartsWith("rtsp")) { // We're playing Internet Radio Stream _isLastFMRadio = Util.Utils.IsLastFMStream(filePath); if (!_isLastFMRadio) { // We're playing Internet Radio Stream, but not LastFM _isRadio = true; } stream = Bass.BASS_StreamCreateURL(filePath, 0, streamFlags, null, IntPtr.Zero); if (stream != 0) { // Get the Tags and set the Meta Tag SyncProc _tagInfo = new TAG_INFO(filePath); SetStreamTags(stream); if (BassTags.BASS_TAG_GetFromURL(stream, _tagInfo)) { GetMetaTags(); } Bass.BASS_ChannelSetSync(stream, BASSSync.BASS_SYNC_META, 0, MetaTagSyncProcDelegate, IntPtr.Zero); } Log.Debug("BASSAudio: Webstream found - trying to fetch stream {0}", Convert.ToString(stream)); } else if (IsMODFile(filePath)) { // Load a Mod file stream = Bass.BASS_MusicLoad(filePath, 0, 0, BASSFlag.BASS_SAMPLE_SOFTWARE | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_MUSIC_AUTOFREE | BASSFlag.BASS_MUSIC_PRESCAN | BASSFlag.BASS_MUSIC_RAMP, 0); } else { // Create a Standard Stream stream = Bass.BASS_StreamCreateFile(filePath, 0, 0, streamFlags); } // Is Mixing / ASIO enabled, then we create a mixer channel and assign the stream to the mixer if ((_Mixing || _useASIO) && stream != 0) { // Do an upmix of the stereo according to the matrix. // Now Plugin the stream to the mixer and set the mixing matrix BassMix.BASS_Mixer_StreamAddChannel(_mixer, stream, BASSFlag.BASS_MIXER_MATRIX | BASSFlag.BASS_STREAM_AUTOFREE | BASSFlag.BASS_MIXER_NORAMPIN | BASSFlag.BASS_MIXER_BUFFER); BassMix.BASS_Mixer_ChannelSetMatrix(stream, _MixingMatrix); } Streams[CurrentStreamIndex] = stream; if (stream != 0) { // When we have a MIDI file, we need to assign the sound banks to the stream if (IsMidiFile(filePath) && soundFonts != null) { BassMidi.BASS_MIDI_StreamSetFonts(stream, soundFonts, soundFonts.Length); } StreamEventSyncHandles[CurrentStreamIndex] = RegisterPlaybackEvents(stream, CurrentStreamIndex); if (doFade && CrossFadeIntervalMS > 0) { _CrossFading = true; // Reduce the stream volume to zero so we can fade it in... Bass.BASS_ChannelSetAttribute(stream, BASSAttribute.BASS_ATTRIB_VOL, 0); // Fade in from 0 to 1 over the _CrossFadeIntervalMS duration Bass.BASS_ChannelSlideAttribute(stream, BASSAttribute.BASS_ATTRIB_VOL, 1, _CrossFadeIntervalMS); } // Attach active DSP effects to the Stream if (_dspActive) { // BASS effects if (_gain != null) { _gain.ChannelHandle = stream; _gain.Start(); } if (_damp != null) { int dampHandle = Bass.BASS_ChannelSetFX(stream, BASSFXType.BASS_FX_BFX_DAMP, _dampPrio); Bass.BASS_FXSetParameters(dampHandle, _damp); } if (_comp != null) { int compHandle = Bass.BASS_ChannelSetFX(stream, BASSFXType.BASS_FX_BFX_COMPRESSOR, _compPrio); Bass.BASS_FXSetParameters(compHandle, _comp); } // VST Plugins foreach (string plugin in _VSTPlugins) { int vstHandle = BassVst.BASS_VST_ChannelSetDSP(stream, plugin, BASSVSTDsp.BASS_VST_DEFAULT, 1); // Copy the parameters of the plugin as loaded on from the settings int vstParm = _vstHandles[plugin]; BassVst.BASS_VST_SetParamCopyParams(vstParm, vstHandle); } // Init Winamp DSP only if we got a winamp plugin actiavtes int waDspPlugin = 0; if (DSP.Settings.Instance.WinAmpPlugins.Count > 0 && !_waDspInitialised) { BassWaDsp.BASS_WADSP_Init(GUIGraphicsContext.ActiveForm); _waDspInitialised = true; foreach (WinAmpPlugin plugins in DSP.Settings.Instance.WinAmpPlugins) { waDspPlugin = BassWaDsp.BASS_WADSP_Load(plugins.PluginDll, 5, 5, 100, 100, null); if (waDspPlugin > 0) { _waDspPlugins[plugins.PluginDll] = waDspPlugin; BassWaDsp.BASS_WADSP_Start(waDspPlugin, 0, 0); } else { Log.Debug("Couldn't load WinAmp Plugin {0}. Error code: {1}", plugins.PluginDll, Enum.GetName(typeof (BASSError), Bass.BASS_ErrorGetCode())); } } } foreach (int waPluginHandle in _waDspPlugins.Values) { BassWaDsp.BASS_WADSP_ChannelSetDSP(waPluginHandle, stream, 1); } } } else { Log.Error("BASS: Unable to create Stream for {0}. Reason: {1}.", filePath, Enum.GetName(typeof (BASSError), Bass.BASS_ErrorGetCode())); } bool playbackStarted = false; if (_Mixing) { if (Bass.BASS_ChannelIsActive(_mixer) == BASSActive.BASS_ACTIVE_PLAYING) { setCueTrackEndPosition(stream); playbackStarted = true; } else { playbackStarted = Bass.BASS_ChannelPlay(_mixer, false); setCueTrackEndPosition(stream); } } else if (_useASIO) { // Get some information about the stream BASS_CHANNELINFO info = new BASS_CHANNELINFO(); Bass.BASS_ChannelGetInfo(stream, info); // In order to provide data for visualisation we need to clone the stream _streamcopy = new StreamCopy(); _streamcopy.ChannelHandle = stream; _streamcopy.StreamFlags = BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT; // decode the channel, so that we have a Streamcopy _asioHandler.Pan = _asioBalance; _asioHandler.Volume = (float)_StreamVolume / 100f; // Set the Sample Rate from the stream _asioHandler.SampleRate = (double)info.freq; // try to set the device rate too (saves resampling) BassAsio.BASS_ASIO_SetRate((double)info.freq); try { _streamcopy.Start(); // start the cloned stream } catch (Exception) { Log.Error("Captured an error on StreamCopy start"); } if (BassAsio.BASS_ASIO_IsStarted()) { setCueTrackEndPosition(stream); playbackStarted = true; } else { BassAsio.BASS_ASIO_Stop(); playbackStarted = BassAsio.BASS_ASIO_Start(0); setCueTrackEndPosition(stream); } } else { setCueTrackEndPosition(stream); playbackStarted = Bass.BASS_ChannelPlay(stream, false); } if (stream != 0 && playbackStarted) { Log.Info("BASS: playback started"); GUIMessage msg = new GUIMessage(GUIMessage.MessageType.GUI_MSG_PLAYBACK_STARTED, 0, 0, 0, 0, 0, null); msg.Label = FilePath; GUIWindowManager.SendThreadMessage(msg); NotifyPlaying = true; NeedUpdate = true; _IsFullScreen = GUIGraphicsContext.IsFullScreenVideo; _VideoPositionX = GUIGraphicsContext.VideoWindow.Left; _VideoPositionY = GUIGraphicsContext.VideoWindow.Top; _VideoWidth = GUIGraphicsContext.VideoWindow.Width; _VideoHeight = GUIGraphicsContext.VideoWindow.Height; // Re-Add the Viswindow to the Mainform Control (It got removed on a manual Stop) SetVisualizationWindow(); SetVideoWindow(); PlayState oldState = _State; _State = PlayState.Playing; if (oldState != _State && PlaybackStateChanged != null) { PlaybackStateChanged(this, oldState, _State); } if (PlaybackStart != null) { PlaybackStart(this, GetTotalStreamSeconds(stream)); } } else { Log.Error("BASS: Unable to play {0}. Reason: {1}.", filePath, Enum.GetName(typeof (BASSError), Bass.BASS_ErrorGetCode())); // Release all of the sync proc handles if (StreamEventSyncHandles[CurrentStreamIndex] != null) { UnregisterPlaybackEvents(stream, StreamEventSyncHandles[CurrentStreamIndex]); } result = false; } } } catch (Exception ex) { result = false; Log.Error("BASS: Play caused an exception: {0}.", ex); } return result; }
/// <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); } }
public void AddIndex(int number, int minutes, int seconds, int frames) { m_Indices = (Index[])CueSheet.ResizeArray(m_Indices, m_Indices.Length + 1); m_Indices[m_Indices.Length - 1] = new Index(number, minutes, seconds, frames); }
/// <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) { // 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); } }
public string build(string cueFileName, CueSheet cueSheet, Track track) { return(CueUtil.buildCueFakeTrackFileName(cueFileName, track)); }