Ejemplo n.º 1
0
        /// <summary>
        /// Creates a new instance of <see cref="MixedAudioProvider"/>.
        /// </summary>
        public MixedAudioProvider(IEnumerable <BassItem> Devices, int FrameRate, bool MuteOutput = true)
        {
            if (Devices == null)
            {
                throw new ArgumentNullException();
            }

            var updatePeriod = 1000 / FrameRate;

            Bass.UpdatePeriod = updatePeriod.Clip(5, 100);

            Console.WriteLine($"BASS Update Period: {Bass.UpdatePeriod}");

            for (var i = 0; i < BufferCount; ++i)
            {
                _buffers.Add(new byte[0]);
            }

            _mixer = BassMix.CreateMixerStream(44100, 2, BassFlags.MixerNonStop);

            foreach (var recordingDevice in Devices)
            {
                InitDevice(recordingDevice);
            }

            if (MuteOutput)
            {
                // mute the mixer
                Bass.ChannelSetAttribute(_mixer, ChannelAttribute.Volume, 0);
            }

            Bass.ChannelSetDSP(_mixer, Procedure);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Creates a new instance of <see cref="MixedAudioProvider"/>.
        /// </summary>
        public MixedAudioProvider(IEnumerable <BassItem> RecordingDevices, IEnumerable <BassItem> LoopbackDevices)
        {
            if (RecordingDevices == null || LoopbackDevices == null)
            {
                throw new ArgumentNullException();
            }

            _mixer  = BassMix.CreateMixerStream(44100, 2, BassFlags.Default);
            _filler = Bass.CreateStream(44100, 2, BassFlags.Float | BassFlags.Decode, ManagedBass.Extensions.SilenceStreamProcedure);

            foreach (var recordingDevice in RecordingDevices)
            {
                InitRecordingDevice(recordingDevice);
            }

            foreach (var loopbackDevice in LoopbackDevices)
            {
                InitLoopbackDevice(loopbackDevice);
            }

            // mute the mixer
            Bass.ChannelSetAttribute(_mixer, ChannelAttribute.Volume, 0);

            Bass.ChannelSetDSP(_mixer, Procedure);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Creates a new instance of <see cref="MixedAudioProvider"/>.
        /// </summary>
        public MixedAudioProvider(IEnumerable <BassItem> Devices, bool MuteOutput = true)
        {
            if (Devices == null)
            {
                throw new ArgumentNullException();
            }

            for (var i = 0; i < BufferCount; ++i)
            {
                _buffers.Add(new byte[0]);
            }

            _mixer = BassMix.CreateMixerStream(44100, 2, BassFlags.MixerNonStop);

            foreach (var recordingDevice in Devices)
            {
                InitDevice(recordingDevice);
            }

            if (MuteOutput)
            {
                // mute the mixer
                Bass.ChannelSetAttribute(_mixer, ChannelAttribute.Volume, 0);
            }

            Bass.ChannelSetDSP(_mixer, Procedure);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Creates a new instance of <see cref="MixedAudioProvider"/>.
        /// </summary>
        public MixedAudioProvider(IEnumerable <BassItem> Devices, int FrameRate, bool MuteOutput = true)
        {
            if (Devices == null)
            {
                throw new ArgumentNullException();
            }

            var updatePeriod = 1000 / FrameRate;

            Bass.UpdatePeriod = updatePeriod.Clip(5, 100);

            for (var i = 0; i < BufferCount; ++i)
            {
                _buffers.Add(new byte[0]);
            }

            _mixer  = BassMix.CreateMixerStream(44100, 2, BassFlags.Default);
            _filler = Bass.CreateStream(44100, 2, BassFlags.Float | BassFlags.Decode, ManagedBass.Extensions.SilenceStreamProcedure);

            foreach (var recordingDevice in Devices)
            {
                InitDevice(recordingDevice);
            }

            if (MuteOutput)
            {
                // mute the mixer
                Bass.ChannelSetAttribute(_mixer, ChannelAttribute.Volume, 0);
            }

            Bass.ChannelSetDSP(_mixer, Procedure);
        }
Ejemplo n.º 5
0
 public override void Connect(IBassStreamComponent previous)
 {
     Logger.Write(this, LogLevel.Debug, "Creating BASS MIX stream with rate {0} and {1} channels.", this.Rate, this.Channels);
     this.ChannelHandle = BassMix.CreateMixerStream(this.Rate, this.Channels, this.Flags);
     if (this.ChannelHandle == 0)
     {
         BassUtils.Throw();
     }
     Logger.Write(this, LogLevel.Debug, "Adding stream to the mixer: {0}", previous.ChannelHandle);
     BassUtils.OK(BassMix.MixerAddChannel(this.ChannelHandle, previous.ChannelHandle, BassFlags.Default | BassFlags.MixerBuffer));
     this.MixerChannelHandles.Add(previous.ChannelHandle);
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Initialises the device.
        /// </summary>
        public bool Init(int Frequency = 44100, int Channels = 2, bool Shared = true, bool UseEventSync = false, int Buffer = 0, int Period = 0)
        {
            var result = _Init(Frequency, Channels, Shared, UseEventSync, Buffer, Period);

            Ensure();
            var info = BassWasapi.Info;

            Bass.Init(0);

            _mixerStream = BassMix.CreateMixerStream(info.Frequency, info.Channels, BassFlags.Float | BassFlags.Decode);

            return(result);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Creates a new instance of <see cref="MixedAudioProvider"/>.
        /// </summary>
        /// <param name="RecordingDevice">Index of Recording Device. null = No Microphone Recording.</param>
        /// <param name="LoopbackDevice">Index of Loopback Device. null = No Loopback Recording.</param>
        /// <exception cref="InvalidOperationException">Can't Record when both <paramref name="LoopbackDevice"/> and <paramref name="RecordingDevice"/> are null.</exception>
        public MixedAudioProvider(int?RecordingDevice, int?LoopbackDevice)
        {
            if (RecordingDevice == null && LoopbackDevice == null)
            {
                throw new InvalidOperationException("Nothing to Record.");
            }

            _mixer = BassMix.CreateMixerStream(44100, 2, BassFlags.Default);

            if (RecordingDevice != null)
            {
                Bass.RecordInit(RecordingDevice.Value);
                Bass.CurrentRecordingDevice = RecordingDevice.Value;

                var info = Bass.RecordingInfo;

                _recording = Bass.RecordStart(info.Frequency, info.Channels, BassFlags.Float | BassFlags.RecordPause, null);

                BassMix.MixerAddChannel(_mixer, _recording, BassFlags.MixerDownMix);
            }

            if (LoopbackDevice != null)
            {
                var playbackDevice = FindPlaybackDevice(LoopbackDevice.Value);

                Bass.Init(playbackDevice);
                Bass.CurrentDevice = playbackDevice;

                _silence = Bass.CreateStream(44100, 2, BassFlags.Float, ManagedBass.Extensions.SilenceStreamProcedure);

                Bass.RecordInit(LoopbackDevice.Value);
                Bass.CurrentRecordingDevice = LoopbackDevice.Value;

                var info = Bass.RecordingInfo;

                _loopback = Bass.RecordStart(info.Frequency, info.Channels, BassFlags.Float | BassFlags.RecordPause, null);

                BassMix.MixerAddChannel(_mixer, _loopback, BassFlags.MixerDownMix);
            }

            // mute the mixer
            Bass.ChannelSetAttribute(_mixer, ChannelAttribute.Volume, 0);

            Bass.ChannelSetDSP(_mixer, Procedure);
        }
Ejemplo n.º 8
0
        internal clsBASSOutDevAsio()
        {
            //* create mixer stream
            //* get asio infos
            AsioDeviceInfo asiodevinfo = new AsioDeviceInfo();

            BassAsio.GetDeviceInfo(AsioDevNum, out asiodevinfo);
            Debug.WriteLine("AsioDevInfo " + AsioDevNum + ": " + asiodevinfo.ToString());

            AsioInfo asioinfo;
            bool     ok = BassAsio.GetInfo(out asioinfo);

            if (!ok || asioinfo.Name == "")
            {
                Debug.WriteLine("No Asio Info");
            }
            else
            {
                Debug.WriteLine("AsioInfo " + ": " + asioinfo.ToString());
            }

            //AsioChannelInfo chaninfo = BassAsio.ChannelGetInfo(false, AsioDevNum);
            //if (chaninfo.Name == null || chaninfo.Name == "") Debug.WriteLine("No Asio Channel Info");
            //else Debug.WriteLine("AsioChannelInfo " + ": " + chaninfo.ToString());

            //* init
            //* no update - not played via BASS
            //* init nosound device
            Bass.Configure(Configuration.UpdatePeriod, 0);
            CheckOKHard(Bass.Init(0, 48000, 0, P.frmSC.Handle)); //44100 ignored (dev0=nosound/decode)
            //CheckOKHard(Bass.SetConfig(BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0));
            //Bass.UpdatePeriod = 0;
            //* int mixer stream (no sound 2 channels=stereo)
            //MixerStream = TestBass.BASS_Mixer_StreamCreate(44100, 2,
            //  BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE);
            MixerStream = CheckHandleHard(BassMix.CreateMixerStream(44100, 2,
                                                                    BassFlags.Decode));
            //* init asio stream on asiodevnum (optional)
            //TestBass.BASS_ASIO_Init(AsioDevNum, BASSASIOInit.BASS_ASIO_DEFAULT);  //(asiodev, flags)
            CheckOKHard(BassAsio.Init(AsioDevNum, AsioInitFlags.None)); //(asiodev, flags)
            Start();                                                    //should be OK to start and add channels later
        }
Ejemplo n.º 9
0
 public override void Connect(IBassStreamComponent previous)
 {
     this.ConfigureWASAPI(previous);
     if (this.ShouldCreateMixer(previous))
     {
         Logger.Write(this, LogLevel.Debug, "Creating BASS MIX stream with rate {0} and {1} channels.", this.Rate, this.Channels);
         this.ChannelHandle = BassMix.CreateMixerStream(this.Rate, this.Channels, this.Flags);
         if (this.ChannelHandle == 0)
         {
             BassUtils.Throw();
         }
         Logger.Write(this, LogLevel.Debug, "Adding stream to the mixer: {0}", previous.ChannelHandle);
         BassUtils.OK(BassMix.MixerAddChannel(this.ChannelHandle, previous.ChannelHandle, BassFlags.Default | BassFlags.MixerBuffer));
         BassUtils.OK(BassWasapiHandler.StreamSet(this.ChannelHandle));
         this.MixerChannelHandles.Add(previous.ChannelHandle);
     }
     else
     {
         Logger.Write(this, LogLevel.Debug, "The stream properties match the device, playing directly.");
         BassUtils.OK(BassWasapiHandler.StreamSet(previous.ChannelHandle));
     }
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Creates a new instance of <see cref="MixedAudioProvider"/>.
        /// </summary>
        public MixedAudioProvider(IEnumerable <BassItem> Devices, bool MuteOutput = true)
        {
            if (Devices == null)
            {
                throw new ArgumentNullException();
            }

            _mixer  = BassMix.CreateMixerStream(44100, 2, BassFlags.Default);
            _filler = Bass.CreateStream(44100, 2, BassFlags.Float | BassFlags.Decode, ManagedBass.Extensions.SilenceStreamProcedure);

            foreach (var recordingDevice in Devices)
            {
                InitDevice(recordingDevice);
            }

            if (MuteOutput)
            {
                // mute the mixer
                Bass.ChannelSetAttribute(_mixer, ChannelAttribute.Volume, 0);
            }

            Bass.ChannelSetDSP(_mixer, Procedure);
        }
Ejemplo n.º 11
0
        private void createMixer()
        {
            if (Handle != 0)
            {
                return;
            }

            // Make sure that bass is initialised before trying to create a mixer.
            // If not, this will be called again when the device is initialised via UpdateDevice().
            if (!ManagedBass.Bass.GetDeviceInfo(ManagedBass.Bass.CurrentDevice, out var deviceInfo) || !deviceInfo.IsInitialized)
            {
                return;
            }

            Handle = BassMix.CreateMixerStream(frequency, 2, BassFlags.MixerNonStop);
            if (Handle == 0)
            {
                return;
            }

            // Lower latency is valued more for the time since we are not using complex DSP effects. Disable buffering on the mixer channel in order for data to be produced immediately.
            ManagedBass.Bass.ChannelSetAttribute(Handle, ChannelAttribute.Buffer, 0);

            // Register all channels that were previously played prior to the mixer being loaded.
            var toAdd = activeChannels.ToArray();

            activeChannels.Clear();
            foreach (var channel in toAdd)
            {
                AddChannelToBassMix(channel);
            }

            Effects.BindCollectionChanged(onEffectsChanged, true);

            ManagedBass.Bass.ChannelPlay(Handle);
            HandleCreated?.Invoke(Handle);
        }
Ejemplo n.º 12
0
        /// <inheritdoc />
        public void Load(string fileName)
        {
            _networkstream = ExtensionProvider.IsNetworkStream(fileName);

            Log.Info("Loading file: {0}", fileName);

            if (_decodeChannel != 0 || _mixerChannel != 0)
            {
                Stop();
            }

            try { Bass.StreamFree(_decodeChannel); }
            catch (Exception ex) { Debug.WriteLine(ex); }

            if (string.IsNullOrEmpty(fileName))
            {
                Log.Error("Filename was null or empty. Aborted load");
                return;
            }

            var sourceflags = BassFlags.Decode | BassFlags.Loop | BassFlags.Float | BassFlags.Prescan;
            var mixerflags  = BassFlags.MixerDownMix | BassFlags.MixerPositionEx | BassFlags.AutoFree;

            if (_networkstream)
            {
                int r;
                lock (Lock)
                {
                    // make sure only 1 thread at a time can do the following
                    // increment the request counter for this request
                    r = ++_req;
                }
                var netFlags = BassFlags.StreamDownloadBlocks | sourceflags;
                Bass.NetProxy  = ""; //os default proxy
                _decodeChannel = Bass.CreateStream(fileName, 0, netFlags, _streamDloadProc, new IntPtr(r));
                lock (Lock)
                {
                    if (r != _req)
                    {
                        if (_decodeChannel != 0)
                        {
                            Bass.StreamFree(_decodeChannel);
                        }
                        return;
                    }
                }
                _netadress = fileName;
            }
            else
            {
                if (ExtensionProvider.IsCdStream(fileName))
                {
                    var cd = new CDTrackInfo(fileName);
                    _decodeChannel = BassCd.CreateStream(cd.Drive, cd.Track, sourceflags);
                    Log.Info("Geting track metadata...");
                    UpdateCDTags(cd.Drive, cd.Track);
                }
                else
                {
                    _decodeChannel = Bass.CreateStream(fileName, 0, 0, sourceflags);
                    Log.Info("Geting track metadata...");
                    UpdateFileTags(fileName);
                }
            }

            if (_decodeChannel == 0)
            {
                Log.Error("Decode chanel creation failed: {0}", Bass.LastError);
                return;
            }

            var channelInfo = Bass.ChannelGetInfo(_decodeChannel);

            _mixerChannel = BassMix.CreateMixerStream(channelInfo.Frequency, channelInfo.Channels, mixerflags);
            if (_mixerChannel == 0)
            {
                Log.Error("Mixer chanel creation failed: {0}", Bass.LastError);
                return;
            }
            if (!BassMix.MixerAddChannel(_mixerChannel, _decodeChannel, BassFlags.MixerDownMix))
            {
                Log.Error("Failed to route decoded stream to mixer: {0}", Bass.LastError);
                return;
            }

            if (!_networkstream)
            {
                Log.Info("Getting track length...");
                var len = Bass.ChannelGetLength(_decodeChannel, PositionFlags.Bytes);
                _length = Bass.ChannelBytes2Seconds(_decodeChannel, len);
                NotifyChanged(nameof(Length));

                Log.Info("Getting Chapters...");
                Chapters.Clear();
                Chapters.AddRange(ChapterFactory.GetChapters(fileName, _length));
            }

            Volume = _LastVolume;
            Bass.ChannelSetAttribute(_mixerChannel, ChannelAttribute.Volume, Volume);
            Log.Info("Loaded file {0}", fileName);
        }
Ejemplo n.º 13
0
 public MixerStream(int Frequency = 44100, int NoOfChannels = 2, bool Buffer = true, Resolution BufferKind = Resolution.Short)
     : base(BufferKind)
 {
     Handle = BassMix.CreateMixerStream(Frequency, NoOfChannels, BufferKind.ToBassFlag());
 }
Ejemplo n.º 14
0
        public void Load(string url)
        {
            CurrentMediaKind = MediaKind.None;

            FreeHandles();

            if (FormatHelpers.IsMidi(url) && File.Exists(_configuration.SoundFontPath))
            {
                BassMidi.DefaultFont = _configuration.SoundFontPath;
            }

            const BassFlags sourceflags = BassFlags.Decode | BassFlags.Loop | BassFlags.Float | BassFlags.Prescan;
            const BassFlags mixerflags  = BassFlags.MixerDownMix | BassFlags.MixerPositionEx | BassFlags.AutoFree;

            if (FormatHelpers.IsNetwork(url))
            {
                _sourceHandle    = Bass.CreateStream(url, 0, sourceflags, _callback, IntPtr.Zero);
                CurrentMediaKind = MediaKind.Network;
            }
            else if (FormatHelpers.IsCd(url))
            {
                (int drive, int track)cdInfo = FormatHelpers.ProcessCdUrl(url);
                _sourceHandle    = BassCd.CreateStream(cdInfo.drive, cdInfo.track, sourceflags);
                CurrentMediaKind = MediaKind.CDStream;
            }
            else if (FormatHelpers.IsTracker(url))
            {
                _sourceHandle    = Bass.MusicLoad(url, 0, 0, sourceflags);
                CurrentMediaKind = MediaKind.Tracker;
                MetaInfo         = TrackMetaInfoFactory.CreateTrackerInfo(url, _sourceHandle);
            }
            else
            {
                _sourceHandle    = Bass.CreateStream(url, 0, 0, sourceflags);
                CurrentMediaKind = MediaKind.File;
                MetaInfo         = TrackMetaInfoFactory.CreateFileInfo(url);
            }

            if (_sourceHandle == 0)
            {
                ExceptionFactory.Create(Bass.LastError, "File Load failed");
            }

            _sourceInfo  = Bass.ChannelGetInfo(_sourceHandle);
            _mixerHandle = BassMix.CreateMixerStream(_sourceInfo.Frequency, _sourceInfo.Channels, mixerflags);

            if (_mixerHandle == 0)
            {
                ExceptionFactory.Create(Bass.LastError, "Mixer failed");
            }

            if (!BassMix.MixerAddChannel(_mixerHandle, _sourceHandle, BassFlags.MixerDownMix))
            {
                ExceptionFactory.Create(Bass.LastError, "Channel mixing failed");
            }

            Bass.ChannelSetAttribute(_mixerHandle, ChannelAttribute.Volume, _lastvol);
            InitEq(ref _mixerHandle);
            Bass.ChannelPlay(_mixerHandle, false);
            IsPlaying = true;
            NotifyPropertyChanged(nameof(MetaInfo));
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Load a file for playback
        /// </summary>
        /// <param name="file">File to load</param>
        public void Load(string file)
        {
            _isstream = false;
            if (Helpers.IsMidi(file))
            {
                if (!File.Exists(Properties.Settings.Default.SoundfontPath))
                {
                    Error(Resources.Engine_ErrorSoundfont);
                    return;
                }
                BassMidi.DefaultFont = Properties.Settings.Default.SoundfontPath;
            }
            if (_source != 0)
            {
                Bass.StreamFree(_source);
                _source   = 0;
                IsPlaying = false;
            }
            if (_mixer != 0)
            {
                Bass.StreamFree(_mixer);
                _mixer    = 0;
                IsPlaying = false;
            }
            var sourceflags = BassFlags.Decode | BassFlags.Loop | BassFlags.Float | BassFlags.Prescan;
            var mixerflags  = BassFlags.MixerDownMix | BassFlags.MixerPositionEx | BassFlags.AutoFree;

            if (file.StartsWith("http://") || file.StartsWith("https://"))
            {
                _source   = Bass.CreateStream(file, 0, sourceflags, _callback, IntPtr.Zero);
                _isstream = true;
                App.RecentUrls.Add(file);
            }
            else if (file.StartsWith("cd://"))
            {
                string[] info = file.Replace("cd://", "").Split('/');
                _source = BassCd.CreateStream(Convert.ToInt32(info[0]), Convert.ToInt32(info[1]), sourceflags);
            }
            else if (Helpers.IsTracker(file))
            {
                _source = Bass.MusicLoad(file, 0, 0, sourceflags);
            }
            else
            {
                _source = Bass.CreateStream(file, 0, 0, sourceflags);
            }
            if (_source == 0)
            {
                Error("Load failed");
                IsPlaying = false;
                _isstream = false;
                return;
            }
            var ch = Bass.ChannelGetInfo(_source);

            _mixer = BassMix.CreateMixerStream(ch.Frequency, ch.Channels, mixerflags);
            if (_mixer == 0)
            {
                Error(Resources.Engine_ErrorMixer);
                IsPlaying = false;
                return;
            }
            if (!BassMix.MixerAddChannel(_mixer, _source, BassFlags.MixerDownMix))
            {
                Error(Resources.Engine_ErrorMixerChannel);
                IsPlaying = false;
                return;
            }
            Bass.ChannelSetAttribute(_mixer, ChannelAttribute.Volume, _lastvol);
            Bass.ChannelPlay(_mixer, false);
            _paused   = false;
            IsPlaying = true;
        }
Ejemplo n.º 16
0
        /// <summary>
        /// 切鸡鸡
        /// </summary>
        /// <param name="dir_path"></param>
        /// <param name="specific_bms_file_name">可选,钦定文件夹下某个bms谱面文件,如果不钦定就随机选取一个</param>
        /// <param name="start_time">起始时间,单位毫秒或者百分比,默认最初</param>
        /// <param name="end_time">终止时间,单位毫秒或者百分比,默认谱面末尾</param>
        /// <param name="encoder_command_line">编码命令</param>
        /// <param name="save_file_name">保存的文件名</param>
        public static bool GeneratePreviewAudio(
            string dir_path,
            string specific_bms_file_name = null,
            string start_time             = null,
            string end_time             = null,
            string encoder_command_line = "",
            string save_file_name       = "preview_auto_generator.ogg",
            int fade_out     = 0,
            int fade_in      = 0,
            bool check_vaild = false,
            bool fast_clip   = false,
            bool no_skip     = false)
        {
            var created_audio_handles = new HashSet <int>();
            var sync_record           = new HashSet <int>();
            int mixer = 0;

            try
            {
                save_file_name = string.IsNullOrWhiteSpace(save_file_name) ? "preview_auto_generator.ogg" : save_file_name;

                if (!Directory.Exists(dir_path))
                {
                    throw new Exception($"Directory {dir_path} not found.");
                }

                var bms_file_path = string.IsNullOrWhiteSpace(specific_bms_file_name) ? Directory.EnumerateFiles(dir_path, "*.bm*", SearchOption.TopDirectoryOnly).Where(x => support_bms_format.Any(y => x.EndsWith(y, StringComparison.InvariantCultureIgnoreCase))).FirstOrDefault() : Path.Combine(dir_path, specific_bms_file_name);

                if (!File.Exists(bms_file_path))
                {
                    throw new Exception($"BMS file {bms_file_path} not found.");
                }

                Console.WriteLine($"BMS file path:{bms_file_path}");

                var content = File.ReadAllText(bms_file_path);

                if (((check_vaild && CheckBeforeFileVaild(dir_path, save_file_name)) || CheckSkipable(dir_path, content)) && !no_skip)
                {
                    Console.WriteLine("This bms contains preview audio file, skiped.");
                    return(true);
                }

                var chart = bms_file_path.EndsWith(".bmson", StringComparison.InvariantCultureIgnoreCase) ? new BmsonChart(content) as Chart : new BMSChart(content);
                chart.Parse(ParseType.Header);
                chart.Parse(ParseType.Resources);
                chart.Parse(ParseType.Content);


                var audio_map = chart.IterateResourceData(ResourceType.wav)
                                .Select(x => (x.resourceId, Directory.EnumerateFiles(dir_path, $"{Path.GetFileNameWithoutExtension(x.dataPath)}.*").FirstOrDefault()))
                                .Select(x => (x.resourceId, LoadAudio(x.Item2)))
                                .ToDictionary(x => x.resourceId, x => x.Item2);

                var bms_evemts = chart.Events
                                 .Where(e => e.type ==
                                        BMSEventType.WAV ||
                                        e.type == BMSEventType.Note ||
                                        e.type == BMSEventType.LongNoteEnd ||
                                        e.type == BMSEventType.LongNoteStart)
                                 .OrderBy(x => x.time)
                                 .Where(x => audio_map.ContainsKey(x.data2))//filter
                                 .ToArray();

                //init mixer
                mixer = BassMix.CreateMixerStream(44100, 2, BassFlags.Decode | BassFlags.MixerNonStop);

                //build triggers
                var mixer_events = new List <MixEventBase>(bms_evemts.Select(x => new AudioMixEvent()
                {
                    Time        = x.time,
                    Duration    = TimeSpan.FromSeconds(Bass.ChannelBytes2Seconds(audio_map[x.data2], Bass.ChannelGetLength(audio_map[x.data2]))),
                    PlayOffset  = TimeSpan.Zero,
                    AudioHandle = audio_map[x.data2]
                }));

                #region Calculate and Adjust StartTime/EndTime

                var full_audio_duration = mixer_events.OfType <AudioMixEvent>().Max(x => x.Duration + x.Time).Add(TimeSpan.FromSeconds(1));
                var actual_end_time     = string.IsNullOrWhiteSpace(end_time) ? full_audio_duration : (end_time.EndsWith("%") ? TimeSpan.FromMilliseconds(float.Parse(end_time.TrimEnd('%')) / 100.0f * full_audio_duration.TotalMilliseconds) : TimeSpan.FromMilliseconds(int.Parse(end_time)));
                var actual_start_time   = string.IsNullOrWhiteSpace(start_time) ? TimeSpan.Zero : (start_time.EndsWith("%") ? TimeSpan.FromMilliseconds(float.Parse(start_time.TrimEnd('%')) / 100.0f * full_audio_duration.TotalMilliseconds) : TimeSpan.FromMilliseconds(int.Parse(start_time)));

                actual_start_time = actual_start_time < TimeSpan.Zero ? TimeSpan.Zero : actual_start_time;
                actual_start_time = actual_start_time > full_audio_duration ? full_audio_duration : actual_start_time;

                actual_end_time = actual_end_time < TimeSpan.Zero ? TimeSpan.Zero : actual_end_time;
                actual_end_time = actual_end_time > full_audio_duration ? full_audio_duration : actual_end_time;

                if (actual_end_time < actual_start_time)
                {
                    var t = actual_end_time;
                    actual_end_time   = actual_start_time;
                    actual_start_time = t;
                }

                Console.WriteLine($"Actual clip({(int)full_audio_duration.TotalMilliseconds}ms):{(int)actual_start_time.TotalMilliseconds}ms ~ {(int)actual_end_time.TotalMilliseconds}ms");

                #endregion

                if (fast_clip)
                {
                    FastClipEvent(mixer_events, ref actual_start_time, ref actual_end_time);
                }

                //add special events to control encorder and mixer
                mixer_events.Add(new StopMixEvent {
                    Time = actual_end_time
                });
                mixer_events.Add(new StartMixEvent()
                {
                    Time = actual_start_time
                });

                //save encoder handle
                int encoder = 0;

                #region apply fade in/out

                var effect = new VolumeParameters();
                var fx     = Bass.ChannelSetFX(mixer, effect.FXType, 0);

                if (fade_in != 0)
                {
                    var fade_in_evt = new FadeMixEvent(false, fade_in)
                    {
                        Time = actual_start_time
                    };

                    mixer_events.Add(fade_in_evt);
                }

                if (fade_out != 0)
                {
                    var fade_out_evt = new FadeMixEvent(true, fade_out)
                    {
                        Time = actual_end_time.Subtract(TimeSpan.FromMilliseconds(fade_out))
                    };

                    mixer_events.Add(fade_out_evt);
                }

                #endregion

                foreach (var evt in mixer_events)
                {
                    var trigger_position = Bass.ChannelSeconds2Bytes(mixer, evt.Time.TotalSeconds);

                    sync_record.Add(Bass.ChannelSetSync(mixer, SyncFlags.Position | SyncFlags.Mixtime, trigger_position, (nn, mm, ss, ll) =>
                    {
                        if (evt is StopMixEvent && encoder != 0)
                        {
                            Bass.ChannelStop(mixer);
                            BassEnc.EncodeStop(encoder);
                            encoder = 0;
                        }
                        else if (evt is StartMixEvent && encoder == 0)
                        {
                            var output_path = Path.Combine(dir_path, save_file_name);
                            Console.WriteLine($"Encoding output file path:{output_path}");
                            encoder = BassEnc_Ogg.Start(mixer, encoder_command_line, EncodeFlags.AutoFree, output_path);
                        }
                        else if (evt is AudioMixEvent audio)
                        {
                            var handle = audio.AudioHandle;
                            BassMix.MixerRemoveChannel(handle);
                            Bass.ChannelSetPosition(handle, Bass.ChannelSeconds2Bytes(handle, audio.PlayOffset.TotalSeconds));
                            BassMix.MixerAddChannel(mixer, handle, BassFlags.Default);
                        }
                        else if (evt is FadeMixEvent fade)
                        {
                            effect.fTime = fade.Duration / 1000.0f;

                            if (fade.FadeOut)
                            {
                                effect.fCurrent = 1;
                                effect.fTarget  = 0;
                            }
                            else
                            {
                                effect.fCurrent = 0;
                                effect.fTarget  = 1;
                            }

                            Bass.FXSetParameters(fx, effect);
                        }
                    }));
                }

                WaitChannelDataProcessed(mixer);

                Console.WriteLine("Success!");
                return(true);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed.\n{ex.Message}\n{ex.StackTrace}");
                return(false);
            }
            finally
            {
                #region Clean Resource

                foreach (var record in sync_record)
                {
                    Bass.ChannelRemoveSync(mixer, record);
                }

                foreach (var handle in created_audio_handles)
                {
                    Bass.StreamFree(handle);
                }

                if (mixer != 0)
                {
                    Bass.StreamFree(mixer);
                }

                #endregion
            }

            int LoadAudio(string item2)
            {
                var handle = Bass.CreateStream(item2, 0, 0, BassFlags.Decode | BassFlags.Float);

                created_audio_handles.Add(handle);

                return(handle);
            }
        }