private static void SaveSample(AudioStream sample)
 {
     if (!File.Exists(sample.Filename))
     {
         AudioExportHelper.SaveAsWave(sample.AudioData.Data, sample.Filename);
     }
 }
        public static void UnloadAudioData(AudioStream audioStream)
        {
            lock (LoadedData)
            {
                var audioData = LoadedData.FirstOrDefault(x => x.Filename == audioStream.Filename);

                if (audioData == null)
                    return;

                audioData.AudioStreams.Remove(audioStream);
                audioStream.AudioData = null;

                if (audioData.AudioStreams.Count > 0)
                    return;

                LoadedData.Remove(audioData);
                audioData.DataHandle.Free();
                audioData.Data = null;
            }
        }
        public static AudioData LoadAudioData(AudioStream audioStream)
        {
            lock (LoadedData)
            {
                var audioData = LoadedData.FirstOrDefault(x => x.Filename == audioStream.Filename);
                if (audioData == null)
                {
                    audioData = new AudioData
                    {
                        Filename = audioStream.Filename,
                        Data = File.ReadAllBytes(audioStream.Filename)
                    };

                    audioData.DataHandle = GCHandle.Alloc(audioData.Data, GCHandleType.Pinned);
                    LoadedData.Add(audioData);
                }

                audioStream.AudioData = audioData;
                audioData.AudioStreams.Add(audioStream);

                return audioData;
            }
        }
 /// <summary>
 ///     Gets the audio stream volume.
 /// </summary>
 /// <param name="audioStream">The audio stream.</param>
 /// <returns>The tracks volume</returns>
 public static decimal GetVolume(AudioStream audioStream)
 {
     if (audioStream == null || !audioStream.IsAudioLoaded()) return 0;
     return GetVolume(audioStream.Channel);
 }
        public static void LoadAudio(AudioStream audioStream)
        {
            // abort if audio data already loaded
            if (audioStream.IsAudioLoaded()) return;

            AudioDataHelper.LoadAudioData(audioStream);

            var channel = Bass.BASS_StreamCreateFile(audioStream.AudioData.DataPointer,
                0,
                audioStream.AudioData.Data.Length,
                BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_STREAM_PRESCAN);

            audioStream.AddChannel(channel);

            if (audioStream.Channel == 0)
                throw new Exception("Cannot load " + audioStream.Filename + ". Error code: " + Bass.BASS_ErrorGetCode());

            DebugHelper.WriteLine("Creating reverse FX stream " + audioStream.Description + "...");
            audioStream.AddChannel(BassFx.BASS_FX_ReverseCreate(audioStream.Channel, 1, BASSFlag.BASS_STREAM_DECODE));

            if (audioStream.Channel == 0)
                throw new Exception("Cannot load " + audioStream.Filename + ". Error code: " + Bass.BASS_ErrorGetCode());

            Bass.BASS_ChannelSetAttribute(audioStream.Channel, BASSAttribute.BASS_ATTRIB_REVERSE_DIR,
                (float)BASSFXReverse.BASS_FX_RVS_FORWARD);


            DebugHelper.WriteLine("Creating tempo FX stream " + audioStream.Description + "...");

            audioStream.AddChannel(BassFx.BASS_FX_TempoCreate(audioStream.Channel,
                BASSFlag.BASS_FX_FREESOURCE | BASSFlag.BASS_STREAM_DECODE));

            if (audioStream.Channel == 0)
                throw new Exception("Cannot load " + audioStream.Filename + ". Error code: " + Bass.BASS_ErrorGetCode());

            DebugHelper.WriteLine("Calculating track length " + audioStream.Description + "...");

            audioStream.Length = Bass.BASS_ChannelGetLength(audioStream.Channel);
            audioStream.DefaultSampleRate = GetSampleRate(audioStream.Channel);

            SetReplayGain(audioStream);
            SetPosition(audioStream, 0);


        }
 /// <summary>
 ///     Sets current volume for an audio stream as a percentage (0 - 100)
 /// </summary>
 /// <param name="audioStream"></param>
 /// <param name="volume">The volume as a percentage (0 - 100).</param>
 public static void SetVolume(AudioStream audioStream, decimal volume)
 {
     if (volume > 100 || volume < 0) throw new Exception("Volume not it range");
     SetVolume(audioStream.Channel, (float)(volume / 100));
 }
        /// <summary>
        ///     Sets the length of an audio stream.
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        public static void SetLength(AudioStream audioStream)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded())
                throw new Exception("Audio file null or not audio not loaded");

            audioStream.Length = Bass.BASS_ChannelGetLength(audioStream.Channel);
        }
 /// <summary>
 ///     Sets current volume for an audio stream as a percentage (0 - 1)
 /// </summary>
 /// <param name="audioStream"></param>
 /// <param name="volume">The volume as a percentage (0 - 1).</param>
 public static void SetVolume(AudioStream audioStream, float volume)
 {
     SetVolume(audioStream.Channel, volume);
 }
        /// <summary>
        ///     Resets the audio stream pitch.
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        public static void ResetPitch(AudioStream audioStream)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded()) return;

            Bass.BASS_ChannelSetAttribute(audioStream.Channel, BASSAttribute.BASS_ATTRIB_TEMPO_PITCH, 0F);
        }
        /// <summary>
        /// Sets the audio stream pitch to match another BPM
        /// </summary>
        /// <param name="audioStream">The audio stream to change the temp of.</param>
        /// <param name="streamBpm">The stream BPM.</param>
        /// <param name="matchBpm">The match BPM.</param>
        public static void SetPitchToMatchBpm(AudioStream audioStream, decimal streamBpm, decimal matchBpm)
        {
            if (audioStream == null || audioStream.Channel == int.MinValue) return;

            var percentChange = (float)(BpmHelper.GetAdjustedBpmPercentChange(streamBpm, matchBpm));
            Bass.BASS_ChannelSetAttribute(audioStream.Channel, BASSAttribute.BASS_ATTRIB_TEMPO_PITCH, percentChange);
        }
 /// <summary>
 ///     Sets the audio stream pitch to match another BPM
 /// </summary>
 /// <param name="audioStream">The audio stream to change the temp of.</param>
 /// <param name="matchBpm">The match BPM.</param>
 public static void SetPitchToMatchBpm(AudioStream audioStream, decimal matchBpm)
 {
     if (audioStream == null || audioStream.Channel == int.MinValue) return;
     SetPitchToMatchBpm(audioStream, audioStream.Bpm, matchBpm);
 }
        /// <summary>
        ///     Sets the audio stream pitch, based on a percent pitch value (0 - 200, 100 being 'normal' pitch)
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        /// <param name="pitch">The pitch.</param>
        public static void SetPitch(AudioStream audioStream, double pitch)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded()) return;

            DebugHelper.WriteLine("SetPitch");

            float sampleRate = audioStream.DefaultSampleRate;
            Bass.BASS_ChannelSetAttribute(audioStream.Channel, BASSAttribute.BASS_ATTRIB_TEMPO_FREQ, sampleRate);
        }
 /// <summary>
 ///     Gets the audio stream sample rate.
 /// </summary>
 /// <param name="audioStream">The audio stream.</param>
 /// <returns>The audio stream sample rate</returns>
 public static int GetSampleRate(AudioStream audioStream)
 {
     return GetSampleRate(audioStream.Channel);
 }
        /// <summary>
        ///     Sets the duration and start/end volumes for an audio stream volume slide.
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        /// <param name="startVolume">The start volume.</param>
        /// <param name="endVolume">The end volume.</param>
        /// <param name="sampleDuration">Sample length duration.</param>
        public static void SetVolumeSlide(AudioStream audioStream, float startVolume, float endVolume,
            long sampleDuration)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded()) return;

            var seconds = audioStream.SamplesToSeconds(sampleDuration);
            SetVolumeSlide(audioStream, startVolume, endVolume, seconds);
        }
        /// <summary>
        ///     Sets the duration and start/end volumes for an audio stream volume slide.
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        /// <param name="startVolume">The start volume as a percentage (0 - 1).</param>
        /// <param name="endVolume">The end volume as a percentage (0 - 1).</param>
        /// <param name="seconds">The seconds.</param>
        public static void SetVolumeSlide(AudioStream audioStream, float startVolume, float endVolume, double seconds)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded()) return;

            // set start volume
            SetVolume(audioStream, startVolume);

            var miliseconds = (int)(seconds * 1000);

            // set the volume slide
            Bass.BASS_ChannelSlideAttribute(audioStream.Channel, BASSAttribute.BASS_ATTRIB_VOL, endVolume, miliseconds);
        }
 /// <summary>
 ///     Plays a 'power down' effect on an audio stream.
 /// </summary>
 /// <param name="audioStream">The audio file.</param>
 public static void PowerDown(AudioStream audioStream)
 {
     var powerDownAction = new Action<AudioStream>(PowerDownAsync);
     powerDownAction.BeginInvoke(audioStream, null, null);
 }
        /// <summary>
        ///     Does an audio stream power down effect asynchronously
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        private static void PowerDownAsync(AudioStream audioStream)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded()) return;

            var freq = audioStream.DefaultSampleRate;
            var interval = (int)(BpmHelper.GetDefaultLoopLength(audioStream.Bpm) * 1000) / 128;

            // set the volume slide
            Bass.BASS_ChannelSlideAttribute(audioStream.Channel, BASSAttribute.BASS_ATTRIB_VOL, 0F, interval * 8);

            var percentValue = 0.70;
            while (freq > 100)
            {
                percentValue = percentValue / 1.2;
                interval = (int)(interval * 0.9D);
                freq = (int)(audioStream.DefaultSampleRate * percentValue);
                if (freq <= 100 || audioStream.Channel == int.MinValue) continue;
                Bass.BASS_ChannelSlideAttribute(audioStream.Channel, BASSAttribute.BASS_ATTRIB_FREQ, freq, interval);
                Thread.Sleep(interval);
            }
            Pause(audioStream);
            if (!audioStream.IsAudioLoaded()) return;
            Bass.BASS_ChannelSetAttribute(audioStream.Channel, BASSAttribute.BASS_ATTRIB_FREQ,
                audioStream.DefaultSampleRate);
            SetVolume(audioStream, 100M);
        }
        /// <summary>
        ///     Sets the audio stream position
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        /// <param name="samplePosition">The audio stream position.</param>
        public static void SetPosition(AudioStream audioStream, long samplePosition)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded()) return;
            if (samplePosition < 0 || samplePosition > audioStream.Length) return;

            var secondPosition = TimeFormatHelper.GetFormattedSeconds(audioStream.SamplesToSeconds(samplePosition));
            DebugHelper.WriteLine($"SetPosition {audioStream.Description} {secondPosition} {samplePosition}");
            Bass.BASS_ChannelSetPosition(audioStream.Channel, samplePosition);
            DebugHelper.WriteLine($"SetPosition END {audioStream.Description} {secondPosition} {samplePosition}");
        }
        /// <summary>
        /// Sets the replay gain for a channel.
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        private static void SetReplayGain(AudioStream audioStream)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded())
                throw new Exception("Audio file null or not audio not loaded");

            if (!audioStream.IsGainChannelInitialized() && audioStream.Gain == 0) return;

            var volume = DecibelToPercent(audioStream.Gain);
            DebugHelper.WriteLine("SetReplayGain for " + audioStream + " to " + volume);

            if (!audioStream.IsGainChannelInitialized())
            {
                audioStream.GainChannel = Bass.BASS_ChannelSetFX(audioStream.Channel, BASSFXType.BASS_FX_BFX_VOLUME, int.MaxValue);
            }

            var volumeParameters = new BASS_BFX_VOLUME(volume, BASSFXChan.BASS_BFX_CHANALL);
            Bass.BASS_FXSetParameters(audioStream.GainChannel, volumeParameters);
        }
 /// <summary>
 ///     Gets the current audioStream position.
 /// </summary>
 /// <param name="audioStream">The audio stream.</param>
 /// <returns>The current audio stream position</returns>
 public static long GetPosition(AudioStream audioStream)
 {
     if (audioStream == null) return 0;
     return !audioStream.IsAudioLoaded() ? 0 : Bass.BASS_ChannelGetPosition(audioStream.Channel);
 }
        /// <summary>
        ///     Adds an audio stream to a mixer
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        /// <param name="mixerChannel">The mixer channel.</param>
        public static void AddToMixer(AudioStream audioStream, int mixerChannel)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded())
                throw new Exception("Audio file null or not audio not loaded");

            if (mixerChannel == int.MinValue) throw new Exception("Mixer channel not initialized");

            DebugHelper.WriteLine($"AddToMixer {audioStream.Description} {mixerChannel} {audioStream.Channel}...");
            AddChannelToMixer(audioStream.Channel, mixerChannel);

            DebugHelper.WriteLine("done");
        }
 /// <summary>
 ///     Pause an audio stream
 /// </summary>
 /// <param name="audioStream">The audio stream.</param>
 public static void Pause(AudioStream audioStream)
 {
     if (audioStream == null || !audioStream.IsAudioLoaded()) return;
     BassMix.BASS_Mixer_ChannelPause(audioStream.Channel);
 }
        /// <summary>
        ///     Removes and audio stream from a mixer.
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        /// <param name="mixerChannel">The mixer channel.</param>
        public static void RemoveFromMixer(AudioStream audioStream, int mixerChannel)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded())
                throw new Exception("Audio file null or not audio not loaded");

            if (mixerChannel == int.MinValue) throw new Exception("Mixer channel not initialized");

            //lock (Lock)
            {
                DebugHelper.WriteLine($"RemoveFromMixer {audioStream.Description} {audioStream.Channel}...");
                BassMix.BASS_Mixer_ChannelPause(audioStream.Channel);
                Bass.BASS_ChannelLock(mixerChannel, true);

                foreach (var channel in audioStream.Channels)
                {
                    BassMix.BASS_Mixer_ChannelRemove(channel);
                }

                Bass.BASS_ChannelLock(mixerChannel, false);
                DebugHelper.WriteLine("done");
            }
        }
 /// <summary>
 ///     Pauses an audio stream smoothly
 /// </summary>
 /// <param name="audioStream">The audio stream.</param>
 public static void SmoothPause(AudioStream audioStream)
 {
     var smoothPauseAction = new Action<AudioStream>(SmoothPauseAsync);
     smoothPauseAction.BeginInvoke(audioStream, null, null);
 }
        /// <summary>
        ///     Unloads the audio of an audio stream
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        public static void UnloadAudio(AudioStream audioStream)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded())
                throw new Exception("Audio file null or not audio not loaded");
            DebugHelper.WriteLine($"UnloadAudio {audioStream.Description}...");

            foreach (var channel in audioStream.Channels)
            {
                Bass.BASS_StreamFree(channel);
            }
            audioStream.Channels.Clear();

            AudioDataHelper.UnloadAudioData(audioStream);

            DebugHelper.WriteLine("done");
        }
        /// <summary>
        ///     Does an audio stream power down effect asynchronously
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        private static void SmoothPauseAsync(AudioStream audioStream)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded()) return;

            var volume = ((float)GetVolume(audioStream)) / 100F;
            SetVolumeSlide(audioStream, volume, 0F, 0.15D);
            Thread.Sleep(150);

            if (!audioStream.IsAudioLoaded()) return;
            BassMix.BASS_Mixer_ChannelPause(audioStream.Channel);

            SetVolume(audioStream, volume);
        }
 /// <summary>
 ///     Gets the shuffler attributes.
 /// </summary>
 /// <param name="track">The track.</param>
 /// <returns>
 ///     A collection of shuffler attributes
 /// </returns>
 private static Dictionary<string, string> GetExtendedAttributes(AudioStream track)
 {
     return GetExtendedAttributes(track.Description);
 }
        /// <summary>
        ///     Plays an audio stream
        /// </summary>
        /// <param name="audioStream">The audio stream.</param>
        public static void Play(AudioStream audioStream)
        {
            if (audioStream == null || !audioStream.IsAudioLoaded()) return;

            //lock (Lock)
            //{
                DebugHelper.WriteLine("Play Audio Stream (" + audioStream.Description + ")");
                BassMix.BASS_Mixer_ChannelPlay(audioStream.Channel);
           // }
        }
        private void SaveSampleFile(AudioStream audioStream, Sample sample)
        {
            var sampleFolder = GetSampleFolder(sample);

            if (!Directory.Exists(sampleFolder))
                CreateSampleFolder(sample);

            var sampleFile = GetSampleFileName(sample);

            AudioExportHelper.SavePartialAsWave(audioStream.Filename, sampleFile, sample.Start, sample.Length, sample.Offset, sample.Gain);
        }
 /// <summary>
 ///     Determines whether an audio stream is currently playing.
 /// </summary>
 /// <param name="audioStream">The audio stream.</param>
 /// <returns>
 ///     True if an audio stream is playing; otherwise, false.
 /// </returns>
 public static bool IsPlaying(AudioStream audioStream)
 {
     if (audioStream == null) return false;
     var position1 = GetPosition(audioStream);
     Thread.Sleep(50);
     var position2 = GetPosition(audioStream);
     return (position1 != position2);
 }