Exemplo n.º 1
0
 public bool GetFFTData(float[] fftDataBuffer)
 {
     if (!BassWasapi.BASS_WASAPI_IsStarted())
     {
         return(false);
     }
     return(BassWasapi.BASS_WASAPI_GetData(fftDataBuffer, _maxFFT) > 0);
 }
Exemplo n.º 2
0
 public bool GetWaveData32(int length, out float[] waveData32)
 {
     waveData32 = null;
     if (!BassWasapi.BASS_WASAPI_IsStarted())
     {
         return(false);
     }
     waveData32 = new float[length];
     return(BassWasapi.BASS_WASAPI_GetData(waveData32, length) == (int)BASSError.BASS_OK);
 }
Exemplo n.º 3
0
        public bool GetChannelLevel(out double dbLevelL, out double dbLevelR)
        {
            dbLevelL = 0f;
            dbLevelR = 0f;
            if (!BassWasapi.BASS_WASAPI_IsStarted())
            {
                return(false);
            }
            int level = BassWasapi.BASS_WASAPI_GetLevel();

            dbLevelL = Un4seen.Bass.Utils.LevelToDB(Un4seen.Bass.Utils.LowWord32(level), 65535);  // the left level
            dbLevelR = Un4seen.Bass.Utils.LevelToDB(Un4seen.Bass.Utils.HighWord32(level), 65535); // the right level
            return(true);
        }
Exemplo n.º 4
0
        /// <summary>
        /// End of Playback for a stream has been signaled
        /// Send event to Bass player to start playback of next song
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="stream"></param>
        /// <param name="data"></param>
        /// <param name="userData"></param>
        private void PlaybackEndProc(int handle, int stream, int data, IntPtr userData)
        {
            try
            {
                MusicStream musicstream;
                // Get the GC handle of the pinned object
                try
                {
                    musicstream = (MusicStream)_pinnedObjects[userData.ToInt32()].Target;
                }
                catch (KeyNotFoundException ex)
                {
                    Log.Error("BASS: GCHandle of Musicstream not found in Dictionary {0} {1}", userData.ToInt32(), ex.Message);
                    return;
                }

                Log.Debug("BASS: End of Song {0}", musicstream.FilePath);

                // We need to find out, if the nextsongs sample rate and / or number of channels are different to the one just ended
                // If this is the case we need a new mixer and the OnMusicStreamMessage needs to be invoked in a thread to avoid crashes.
                // In order to have gapless playback, it needs to be invoked in sync.
                MusicStream            nextStream = null;
                Playlists.PlayListItem nextSong   = Playlists.PlayListPlayer.SingletonPlayer.GetNextItem();
                MusicStream._fileType = Utils.GetFileType(musicstream.FilePath);
                if (nextSong != null && MusicStream._fileType.FileMainType != FileMainType.WebStream)
                {
                    nextStream = new MusicStream(nextSong.FileName, true);
                }
                else if (MusicStream._fileType.FileMainType == FileMainType.WebStream)
                {
                    if (MusicStreamMessage != null)
                    {
                        MusicStreamMessage(musicstream, MusicStream.StreamAction.InternetStreamChanged);
                        return;
                    }
                }

                bool newMixerNeeded = false;
                if (nextStream != null && nextStream.BassStream != 0)
                {
                    if (_bassPlayer.NewMixerNeeded(nextStream))
                    {
                        newMixerNeeded = true;
                    }
                    nextStream.Dispose();
                }

                if (newMixerNeeded)
                {
                    if (Config.MusicPlayer == AudioPlayer.WasApi && BassWasapi.BASS_WASAPI_IsStarted())
                    {
                        BassWasapi.BASS_WASAPI_Stop(true);
                    }

                    // Unplug the Source channel from the mixer
                    Log.Debug("BASS: Unplugging source channel from Mixer.");
                    BassMix.BASS_Mixer_ChannelRemove(musicstream.BassStream);

                    // invoke a thread because we need a new mixer
                    Log.Debug("BASS: Next song needs a new mixer.");

                    new Thread(() =>
                    {
                        if (MusicStreamMessage != null)
                        {
                            MusicStreamMessage(musicstream, MusicStream.StreamAction.Crossfading);
                        }
                    })
                    {
                        Name = "BASS"
                    }.Start();
                }
                else
                {
                    if (MusicStreamMessage != null)
                    {
                        MusicStreamMessage(musicstream, MusicStream.StreamAction.Crossfading);
                    }
                }
            }
            catch (AccessViolationException ex)
            {
                Log.Error("BASS: Caught AccessViolationException in Playback End Proc {0}", ex.Message);
            }
        }
Exemplo n.º 5
0
        public bool CreateMixer(MusicStream stream)
        {
            Log.Debug("BASS: ---------------------------------------------");
            Log.Debug("BASS: Creating BASS mixer stream");

            bool result = false;

            BASSFlag mixerFlags = BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_MIXER_NORAMPIN;

            if (Config.MusicPlayer == AudioPlayer.Asio || Config.MusicPlayer == AudioPlayer.WasApi)
            {
                mixerFlags |= BASSFlag.BASS_STREAM_DECODE;
            }

            int outputChannels = _bassPlayer.DeviceChannels;

            _mixingMatrix = null;

            // See, if we need Upmixing
            if (outputChannels > stream.ChannelInfo.chans)
            {
                Log.Debug("BASS: Found more output channels ({0}) than input channels ({1}). Check for upmixing.", outputChannels,
                          stream.ChannelInfo.chans);
                _mixingMatrix = CreateMixingMatrix(stream.ChannelInfo.chans);
                if (_mixingMatrix != null)
                {
                    outputChannels = Math.Min(_mixingMatrix.GetLength(0), outputChannels);
                }
                else
                {
                    outputChannels = stream.ChannelInfo.chans;
                }
            }
            else if (outputChannels < stream.ChannelInfo.chans)
            {
                // Downmix to Stereo
                Log.Debug("BASS: Found more input channels ({0}) than output channels ({1}). Downmix.", stream.ChannelInfo.chans,
                          outputChannels);
                outputChannels = Math.Min(outputChannels, 2);
            }

            Log.Debug("BASS: Creating {0} channel mixer with sample rate of {1}", outputChannels, stream.ChannelInfo.freq);
            _mixer = BassMix.BASS_Mixer_StreamCreate(stream.ChannelInfo.freq, outputChannels, mixerFlags);
            if (_mixer == 0)
            {
                Log.Error("BASS: Unable to create Mixer.  Reason: {0}.",
                          Enum.GetName(typeof(BASSError), Bass.BASS_ErrorGetCode()));
                return(false);
            }

            switch (Config.MusicPlayer)
            {
            case AudioPlayer.Bass:
            case AudioPlayer.DShow:

                if (!Bass.BASS_ChannelPlay(_mixer, false))
                {
                    Log.Error("BASS: Unable to start Mixer.  Reason: {0}.", Enum.GetName(typeof(BASSError), Bass.BASS_ErrorGetCode()));
                    return(false);
                }

                result = true;

                break;

            case AudioPlayer.Asio:

                Log.Info("BASS: Initialising ASIO device");

                if (BassAsio.BASS_ASIO_IsStarted() && !BassAsio.BASS_ASIO_Stop())
                {
                    Log.Error("BASS: Error stopping Asio Device: {0}", BassAsio.BASS_ASIO_ErrorGetCode());
                }

                // Disable and Unjoin all the channels
                if (!BassAsio.BASS_ASIO_ChannelReset(false, -1, BASSASIOReset.BASS_ASIO_RESET_ENABLE))
                {
                    Log.Error("BASS: Error disabling Asio Channels: {0}", BassAsio.BASS_ASIO_ErrorGetCode());
                }

                if (!BassAsio.BASS_ASIO_ChannelReset(false, -1, BASSASIOReset.BASS_ASIO_RESET_JOIN))
                {
                    Log.Error("BASS: Error unjoining Asio Channels: {0}", BassAsio.BASS_ASIO_ErrorGetCode());
                }

                _asioProc = new ASIOPROC(AsioCallback);

                BassAsio.BASS_ASIO_ChannelSetVolume(false, -1, (float)Config.StreamVolume / 100f);

                // enable 1st output channel...(0=first)
                Log.Debug("BASS: Joining Asio Channel #{0}", "0");
                BassAsio.BASS_ASIO_ChannelEnable(false, 0, _asioProc, new IntPtr(_mixer));

                // and join the next channels to it
                int numChannels = Math.Max(stream.ChannelInfo.chans, outputChannels);
                for (int i = 1; i < numChannels; i++)
                {
                    Log.Debug("BASS: Joining Asio Channel #{0}", i);
                    BassAsio.BASS_ASIO_ChannelJoin(false, i, 0);
                }

                // since we joined the channels, the next commands will apply to all channles joined
                // so setting the values to the first channels changes them all automatically
                // set the source format (float, as the decoding channel is)
                if (!BassAsio.BASS_ASIO_ChannelSetFormat(false, 0, BASSASIOFormat.BASS_ASIO_FORMAT_FLOAT))
                {
                    Log.Error("BASS: Error setting Asio Sample Format: {0}", BassAsio.BASS_ASIO_ErrorGetCode());
                }

                // set the source rate
                Log.Debug("BASS: Set sample rate to {0}", stream.ChannelInfo.freq);
                if (!BassAsio.BASS_ASIO_ChannelSetRate(false, 0, (double)stream.ChannelInfo.freq))
                {
                    Log.Error("BASS: Error setting Asio Channel Samplerate: {0}", BassAsio.BASS_ASIO_ErrorGetCode());
                }

                // try to set the device rate too (saves resampling)
                if (!BassAsio.BASS_ASIO_SetRate((double)stream.ChannelInfo.freq))
                {
                    Log.Error("BASS: Error setting Asio Samplerate: {0}", BassAsio.BASS_ASIO_ErrorGetCode());
                }

                // and start playing it...start output using default buffer/latency
                if (!BassAsio.BASS_ASIO_Start(0))
                {
                    Log.Error("BASS: Error starting Asio playback: {0}", BassAsio.BASS_ASIO_ErrorGetCode());
                }
                Log.Info("BASS: Finished initialising ASIO device");
                result = true;

                break;

            case AudioPlayer.WasApi:

                Log.Info("BASS: Initialising WASAPI device");

                if (BassWasapi.BASS_WASAPI_IsStarted())
                {
                    try
                    {
                        BassWasapi.BASS_WASAPI_Free();
                        Log.Debug("BASS: Freed WASAPI device");
                    }
                    catch (Exception ex)
                    {
                        Log.Error("BASS: Exception freeing WASAPI. {0} {1}", ex.Message, ex.StackTrace);
                    }
                }

                BASSWASAPIInit initFlags = BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT;

                _wasapiProc = new WASAPIPROC(WasApiCallback);

                int  frequency = stream.ChannelInfo.freq;
                int  chans     = outputChannels;
                bool wasApiExclusiveSupported = true;

                // If Exclusive mode is used, check, if that would be supported, otherwise init in shared mode
                if (Config.WasApiExclusiveMode)
                {
                    initFlags        |= BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE;
                    _wasapiShared     = false;
                    _wasapiMixedChans = 0;
                    _wasapiMixedFreq  = 0;

                    BASSWASAPIFormat wasapiFormat = BassWasapi.BASS_WASAPI_CheckFormat(_bassPlayer.DeviceNumber,
                                                                                       stream.ChannelInfo.freq,
                                                                                       stream.ChannelInfo.chans,
                                                                                       BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE);
                    if (wasapiFormat == BASSWASAPIFormat.BASS_WASAPI_FORMAT_UNKNOWN)
                    {
                        Log.Warn("BASS: WASAPI exclusive mode not directly supported. Let BASS WASAPI choose better mode.");
                        wasApiExclusiveSupported = false;
                    }
                }
                else
                {
                    Log.Debug("BASS: Init WASAPI shared mode with Event driven system enabled.");
                    initFlags |= BASSWASAPIInit.BASS_WASAPI_SHARED | BASSWASAPIInit.BASS_WASAPI_EVENT;

                    // In case of WASAPI Shared mode we need to setup the mixer to use the same sample rate as set in
                    // the Windows Mixer, otherwise we wioll have increased playback speed
                    BASS_WASAPI_DEVICEINFO devInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo(_bassPlayer.DeviceNumber);
                    Log.Debug("BASS: Creating {0} channel mixer for frequency {1}", devInfo.mixchans, devInfo.mixfreq);
                    _mixer = BassMix.BASS_Mixer_StreamCreate(devInfo.mixfreq, devInfo.mixchans, mixerFlags);
                    if (_mixer == 0)
                    {
                        Log.Error("BASS: Unable to create Mixer.  Reason: {0}.",
                                  Enum.GetName(typeof(BASSError), Bass.BASS_ErrorGetCode()));
                        return(false);
                    }
                    _wasapiShared = true;
                }

                if (BassWasapi.BASS_WASAPI_Init(_bassPlayer.DeviceNumber, stream.ChannelInfo.freq, stream.ChannelInfo.chans,
                                                initFlags, 0f, 0f, _wasapiProc, IntPtr.Zero))
                {
                    BASS_WASAPI_INFO wasapiInfo = BassWasapi.BASS_WASAPI_GetInfo();

                    Log.Debug("BASS: ---------------------------------------------");
                    Log.Debug("BASS: Buffer Length: {0}", wasapiInfo.buflen);
                    Log.Debug("BASS: Channels: {0}", wasapiInfo.chans);
                    Log.Debug("BASS: Frequency: {0}", wasapiInfo.freq);
                    Log.Debug("BASS: Format: {0}", wasapiInfo.format.ToString());
                    Log.Debug("BASS: InitFlags: {0}", wasapiInfo.initflags.ToString());
                    Log.Debug("BASS: Exclusive: {0}", wasapiInfo.IsExclusive.ToString());
                    Log.Debug("BASS: ---------------------------------------------");
                    Log.Info("BASS: WASAPI Device successfully initialised");

                    // Now we need to check, if WASAPI decided to switch to a different mode
                    if (Config.WasApiExclusiveMode && !wasApiExclusiveSupported)
                    {
                        // Recreate Mixer with new value
                        Log.Debug("BASS: Creating new {0} channel mixer for frequency {1}", wasapiInfo.chans, wasapiInfo.freq);
                        _mixer = BassMix.BASS_Mixer_StreamCreate(wasapiInfo.freq, wasapiInfo.chans, mixerFlags);
                        if (_mixer == 0)
                        {
                            Log.Error("BASS: Unable to create Mixer.  Reason: {0}.",
                                      Enum.GetName(typeof(BASSError), Bass.BASS_ErrorGetCode()));
                            return(false);
                        }
                    }

                    BassWasapi.BASS_WASAPI_SetVolume(BASSWASAPIVolume.BASS_WASAPI_CURVE_DB, (float)Config.StreamVolume / 100f);
                    BassWasapi.BASS_WASAPI_Start();
                    result = true;
                }
                else
                {
                    Log.Error("BASS: Couldn't init WASAPI device. Error: {0}", Enum.GetName(typeof(BASSError), Bass.BASS_ErrorGetCode()));
                }
                break;
            }

            if (result)
            {
                Log.Debug("BASS: Successfully created BASS Mixer stream");
            }
            return(result);
        }
Exemplo n.º 6
0
        public void EnableBASS(bool setto)
        {
            if (setto)
            {
                if (BassWasapi.BASS_WASAPI_IsStarted())
                {
                    BassWasapi.BASS_WASAPI_Stop(true);
                }

                BassWasapi.BASS_WASAPI_Free();
                Bass.BASS_Free();

                if (VisualizerThread != null)
                {
                    RunVisualizerThread = false;
                    while (VisualizerThread.Status == TaskStatus.Running)
                    {
                        Thread.Sleep(5);
                        Application.DoEvents();
                    }
                    VisualizerThread.Dispose();
                }

                String SerialOut = "";
                MainFormClass.VisualizerFromSeriesIDNumericUpDown.Invoke((MethodInvoker) delegate
                {
                    MainFormClass.VisualizerToSeriesIDNumericUpDown.Invoke((MethodInvoker) delegate
                    {
                        SerialOut = "6;" + MainFormClass.VisualizerFromSeriesIDNumericUpDown.Value + ";" + MainFormClass.VisualizerToSeriesIDNumericUpDown.Value;
                    });
                });
                MainFormClass.SendDataBySerial(SerialOut);

                BassProcess = new WASAPIPROC(Process);

                var array    = (MainFormClass.AudioSourceComboBox.Items[MainFormClass.AudioSourceComboBox.SelectedIndex] as string).Split(' ');
                int devindex = Convert.ToInt32(array[0]);
                Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATETHREADS, false);
                Bass.BASS_Init(0, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
                bool result = BassWasapi.BASS_WASAPI_Init(devindex, 0, 0, BASSWASAPIInit.BASS_WASAPI_BUFFER, 1f, 0.05f, BassProcess, IntPtr.Zero);
                if (!result)
                {
                    var error = Bass.BASS_ErrorGetCode();
                    MessageBox.Show(error.ToString());
                }

                BassWasapi.BASS_WASAPI_Start();

                RunVisualizerThread = true;

                VisualizerThread = new Task(delegate { AudioDataThread(); });
                VisualizerThread.Start();
            }
            else
            {
                if (VisualizerThread != null)
                {
                    RunVisualizerThread = false;
                    while (VisualizerThread.Status == TaskStatus.Running)
                    {
                        Thread.Sleep(5);
                        Application.DoEvents();
                    }
                    VisualizerThread.Dispose();
                }

                if (BassWasapi.BASS_WASAPI_IsStarted())
                {
                    BassWasapi.BASS_WASAPI_Stop(true);
                }

                BassWasapi.BASS_WASAPI_Free();
                Bass.BASS_Free();
            }
        }
Exemplo n.º 7
0
        async Task StartVisualizer(bool Start, string DeviceName)
        {
            if (Start)
            {
                if (RunVisualizer)
                {
                    RunVisualizer = false;
                    while (VisualizersRunning)
                    {
                        await Task.Delay(10);
                    }
                }
                if (BassWasapi.BASS_WASAPI_IsStarted())
                {
                    BassWasapi.BASS_WASAPI_Stop(true);
                }

                BassWasapi.BASS_WASAPI_Free();
                Bass.BASS_Free();

                BassProcess = new WASAPIPROC(Process);

                var array    = (AudioSourceCombobox.Items[AudioSourceCombobox.SelectedIndex] as string).Split(' ');
                int devindex = Convert.ToInt32(array[0]);
                Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATETHREADS, false);
                Bass.BASS_Init(0, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
                bool result = BassWasapi.BASS_WASAPI_Init(devindex, 0, 0, BASSWASAPIInit.BASS_WASAPI_BUFFER, 1f, 0.05f, BassProcess, IntPtr.Zero);
                if (!result)
                {
                    var error = Bass.BASS_ErrorGetCode();
                    MessageBox.Show(error.ToString());
                }

                BassWasapi.BASS_WASAPI_Start();

                RunVisualizer      = true;
                VisualizersRunning = true;

                Task VisualizerThreadStart = new Task(delegate {
                    VisualizerThread();
                });
                VisualizerThreadStart.Start();
            }
            else
            {
                if (RunVisualizer)
                {
                    RunVisualizer = false;
                    while (VisualizersRunning)
                    {
                        await Task.Delay(10);
                    }
                }
                for (int i = 0; i < VisualizerStack.Count; i++)
                {
                    VisualizerStack[i].VisualizerControlBeatZoneCanvas.Children.Clear();
                }

                if (BassWasapi.BASS_WASAPI_IsStarted())
                {
                    BassWasapi.BASS_WASAPI_Stop(true);
                }

                BassWasapi.BASS_WASAPI_Free();
                Bass.BASS_Free();
            }
        }