Ejemplo n.º 1
0
    /// <summary>
    /// Initialise the Visualisation Window and Load Decoder/DSP Plugins
    /// The BASS engine itself is not initialised at this stage, since it may cause S/PDIF for Movies not working on some systems.
    /// </summary>
    private void Initialize()
    {
      bool result = true;
      try
      {
        Log.Info("BASS: Initialize BASS environment ...");
        LoadSettings();

        result = BassRegistration.BassRegistration.Register();

        if (result)
        {
          // BASS_CONFIG_UPDATEPERIOD is set in InitDSDevice in case 
          // we are going to playback over DirectSound.
          Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0);

          // Set the Global Volume. 0 = silent, 10000 = Full
          // We get 0 - 100 from Configuration, so multiply by 100
          Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_GVOL_STREAM, Config.StreamVolume * 100);
          Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_BUFFER, Config.BufferingMs);

          // network buffersize for webstreams should be larger then the playbackbuffer.
          // To insure a stable playback-start.
          int netBufferSize = Config.BufferingMs;

          // Minimize at default value.
          if (netBufferSize < 5000)
            netBufferSize = 5000;

          Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_NET_BUFFER, netBufferSize);

          // PreBuffer() takes care of this.
          Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_NET_PREBUF, 0);
        }

        InitializeControls();
        Config.LoadAudioDecoderPlugins();
        Config.LoadDSPPlugins();

        _playBackType = (int)Config.PlayBack;

        // Create a Stream Copy, if Visualisation is enabled
        if (HasViz)
        {
          Log.Debug("BASS: Create Stream copy for Visualisation");
          _streamcopy = new StreamCopy();
          _streamcopy.StreamCopyFlags = BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE;
        }

        Log.Info("BASS: Initializing BASS environment done.");

        _initialized = true;
        _bassFreed = true;
      }

      catch (Exception ex)
      {
        Log.Error("BASS: Initialize thread failed.  Reason: {0}", ex.Message);
      }
    }
Ejemplo n.º 2
0
    /// <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;
    }