public void Resample_8To8() //broken only on Linux? { //-- 1. Create a raw sine sample which shall be 44100 Hz and 16 Bit int sampleLength = 500; byte[] buffer = new byte[sampleLength]; for (int i = 0; i < sampleLength; i++) { buffer [i] = (byte)(128 + 120.0f * Math.Sin(((float)i / (float)sampleLength) * (Math.PI * 2.0f))); } using (BinaryWriter writerRaw = new BinaryWriter(File.Open("test2_in_sine_44100_8.raw", FileMode.Create))) { for (uint i = 0; i < sampleLength; i++) { writerRaw.Write(buffer [i]); } } GCHandle _hGCFile; // now create a pinned handle, so that the Garbage Collector will not move this object _hGCFile = GCHandle.Alloc(buffer, GCHandleType.Pinned); int handle = Bass.BASS_StreamCreate(44100, 1, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_8BITS, BASSStreamProc.STREAMPROC_PUSH); int ret = Bass.BASS_StreamPutData(handle, _hGCFile.AddrOfPinnedObject(), buffer.Length * sizeof(byte) | (int)BASSStreamProc.BASS_STREAMPROC_END); Assert.AreEqual(buffer.Length * sizeof(byte), ret); //-- 2. Mix it int mixer = BassMix.BASS_Mixer_StreamCreate(11025, 1, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_8BITS); // add channel to mixer bool isMixerGood = BassMix.BASS_Mixer_StreamAddChannel(mixer, handle, BASSFlag.BASS_MIXER_NORAMPIN); Assert.AreEqual(true, isMixerGood); //-- 3. grab Stream and compare byte[] buffer2 = new byte[1000]; // total data written to the new byte[] buffer int totalDataWritten = Bass.BASS_ChannelGetData(mixer, buffer2, (int)1000); Console.WriteLine("totalDataWritten " + totalDataWritten); using (BinaryWriter writerRaw = new BinaryWriter(File.Open("test2_out_sine_11025_8.raw", FileMode.Create))) { for (uint i = 0; i < totalDataWritten; i++) { writerRaw.Write(buffer2 [i]); } } string hashGen = MD5Utils.GenerateMd5Hash(buffer2); Bass.BASS_StreamFree(handle); Bass.BASS_StreamFree(mixer); Assert.AreEqual("50bce9c536e98667534747f0a5f06ebd", hashGen); }
private void Simple_Load(object sender, System.EventArgs e) { // BassNet.Registration("your email", "your regkey"); if (!Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, this.Handle)) { MessageBox.Show(this, "Bass_Init error!"); this.Close(); return; } Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_BUFFER, 200); Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATEPERIOD, 20); // already create a mixer _mixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_SAMPLE_FLOAT); if (_mixer == 0) { MessageBox.Show(this, "Could not create mixer!"); Bass.BASS_Free(); this.Close(); return; } _mixerStallSync = new SYNCPROC(OnMixerStall); Bass.BASS_ChannelSetSync(_mixer, BASSSync.BASS_SYNC_STALL, 0L, _mixerStallSync, IntPtr.Zero); timerUpdate.Start(); Bass.BASS_ChannelPlay(_mixer, false); }
public void start(double delay) { latency = (float)delay / 10; var str = (inlist.Items[inlist.SelectedIndex] as string); var array = str.Split(' '); sourceIndex = Convert.ToInt32(array[0]); str = (outlist.Items[outlist.SelectedIndex] as string); array = str.Split(' '); outIndex = Convert.ToInt32(array[0]); Console.WriteLine(sourceIndex + " " + outIndex); Console.WriteLine(delay); stop(); Bass.BASS_Init(0, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero); // "No Sound" device init // Garbage collector can't track the reference BassWasapi holds, // so we're adding a reference here to prevent garbage collection inProc = sourceWasapiProc; outProc = outWasapiProc; BassWasapi.BASS_WASAPI_Init(sourceIndex, 44100, 0, 0, 1, 0, inProc, IntPtr.Zero); BassWasapi.BASS_WASAPI_Init(outIndex, 44100, 0, 0, 4 * latency, 1 * latency, outProc, IntPtr.Zero); BassWasapi.BASS_WASAPI_SetDevice(outIndex); pushstr = Bass.BASS_StreamCreatePush(44100, 2, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT, IntPtr.Zero); outstr = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT); BassMix.BASS_Mixer_StreamAddChannel(outstr, pushstr, 0); BassWasapi.BASS_WASAPI_SetDevice(sourceIndex); BassWasapi.BASS_WASAPI_Start(); BassWasapi.BASS_WASAPI_SetDevice(outIndex); BassWasapi.BASS_WASAPI_Start(); }
/// <summary> /// Recode the file /// </summary> /// <param name = "fileName">Initial file</param> /// <param name = "outFileName">Target file</param> /// <param name = "targetSampleRate">Target sample rate</param> public void RecodeTheFile(string fileName, string outFileName, int targetSampleRate) { int stream = Un4seen.Bass.Bass.BASS_StreamCreateFile(fileName, 0, 0, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_MONO | BASSFlag.BASS_SAMPLE_FLOAT); TAG_INFO tags = new TAG_INFO(); BassTags.BASS_TAG_GetFromFile(stream, tags); int mixerStream = BassMix.BASS_Mixer_StreamCreate(targetSampleRate, 1, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_MONO | BASSFlag.BASS_SAMPLE_FLOAT); if (BassMix.BASS_Mixer_StreamAddChannel(mixerStream, stream, BASSFlag.BASS_MIXER_FILTER)) { WaveWriter waveWriter = new WaveWriter(outFileName, mixerStream, true); const int length = 5512 * 10 * 4; float[] buffer = new float[length]; while (true) { int bytesRead = Un4seen.Bass.Bass.BASS_ChannelGetData(mixerStream, buffer, length); if (bytesRead == 0) { break; } waveWriter.Write(buffer, bytesRead); } waveWriter.Close(); } else { throw new Exception(Un4seen.Bass.Bass.BASS_ErrorGetCode().ToString()); } }
/// <summary> /// Initializes a decoder mixer channel. /// </summary> /// <returns>The channel Id of the mixer channel</returns> public static int InitializeMixerChannel() { var mixerChannel = BassMix.BASS_Mixer_StreamCreate(DefaultSampleRate, 2, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE); if (mixerChannel == 0) { throw new Exception("Cannot create Bass Mixer."); } return(mixerChannel); }
public int CreateBassMixer(BMSSong pSong) { int mixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_END); Dictionary <AudioSample, int> samples = PreloadSamples(pSong.AudioSamples); List <Track> tracks = pSong.Tracks; for (int i = 0; i < tracks.Count; i++) { MixTrack(mixer, tracks[i], samples); } return(mixer); }
public void CreateMixerChannel() { int mixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_MIXER_END); this.StreamMixer = mixer; if (ChannelType != CHANNEL_TYPE.REMOTE_URL) { syncProcEnd = new SYNCPROC(SyncProcEndCallback); mySyncHandleEnd = Bass.BASS_ChannelSetSync(mixer, BASSSync.BASS_SYNC_END, 0, syncProcEnd, IntPtr.Zero); } }
/// <summary> /// Creates the visualization Bass stream. /// </summary> private void CreateVizStream() { BASSFlag streamFlags = BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT; int handle = Bass.BASS_StreamCreate( _inputStream.SampleRate, _inputStream.Channels, streamFlags, _vizRawStreamWriteProcDelegate, IntPtr.Zero); if (handle == BassConstants.BassInvalidHandle) { throw new BassLibraryException("BASS_StreamCreate"); } _vizRawStream = BassStream.Create(handle); // Todo: apply AGC streamFlags = BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE; handle = BassMix.BASS_Mixer_StreamCreate(_inputStream.SampleRate, 2, streamFlags); if (handle == BassConstants.BassInvalidHandle) { throw new BassLibraryException("BASS_StreamCreate"); } _vizStream = BassStream.Create(handle); streamFlags = BASSFlag.BASS_MIXER_NORAMPIN | BASSFlag.BASS_MIXER_DOWNMIX | BASSFlag.BASS_MIXER_MATRIX; if (!BassMix.BASS_Mixer_StreamAddChannel(_vizStream.Handle, _vizRawStream.Handle, streamFlags)) { throw new BassLibraryException("BASS_Mixer_StreamAddChannel"); } // TODO Albert 2010-02-27: What is this? if (_inputStream.Channels == 1) { float[,] mixMatrix = new float[2, 1]; mixMatrix[0, 0] = 1; mixMatrix[1, 0] = 1; if (!BassMix.BASS_Mixer_ChannelSetMatrix(_vizRawStream.Handle, mixMatrix)) { throw new BassLibraryException("BASS_Mixer_ChannelSetMatrix"); } } }
public Scene() { FadeOutLength = DEFAULT_FADEOUT_LENGTH; Name = "Unnamed Scene"; slideSync = new SYNCPROC(SlideSync); SoundEffects.ListChanged += new ListChangedEventHandler(SoundEffects_ListChanged); SceneMixerChannel = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT); BassMix.BASS_Mixer_ChannelFlags(SceneMixerChannel, BASSFlag.BASS_MIXER_NORAMPIN, BASSFlag.BASS_MIXER_NORAMPIN); Bass.BASS_ChannelSetSync(SceneMixerChannel, BASSSync.BASS_SYNC_SLIDE, 0, slideSync, IntPtr.Zero); this.SceneVolume = 1; this.IsFading = false; }
public static int PlugChannelToMixer(int handle, int freq, int chans, int res) { BASSFlag bassFlag = BASSFlag.BASS_STREAM_DECODE; if (res == 8) { bassFlag |= BASSFlag.BASS_SAMPLE_8BITS; } // this will be the final mixer output stream being played int mixer = BassMix.BASS_Mixer_StreamCreate(freq, chans, bassFlag); // add channel to mixer bool isMixerGood = BassMix.BASS_Mixer_StreamAddChannel(mixer, handle, BASSFlag.BASS_MIXER_NORAMPIN); return(mixer); }
public SoundEffect() { IsLooping = false; LoopGap = 0; LoopGapVariance = 0; gapTimer.Interval = 1; SoundEffectVolume = 1; gapTimer.Elapsed += new System.Timers.ElapsedEventHandler(gapTimer_Elapsed); Samples.ListChanged += new ListChangedEventHandler(Samples_ListChanged); endSync = new SYNCPROC(EndSync); Name = "Unnamed Sound Effect"; SoundEffectMixerChannel = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT); BassMix.BASS_Mixer_ChannelFlags(SoundEffectMixerChannel, BASSFlag.BASS_MIXER_NORAMPIN, BASSFlag.BASS_MIXER_NORAMPIN); }
public static int MixerStreamCreate(int samplerate) { BASSFlag mixerFlags = BASSFlag.BASS_SAMPLE_FLOAT; if (Player.IsAsioInitialized || Player.IsWasapiInitialized) { mixerFlags |= BASSFlag.BASS_STREAM_DECODE; } m_mixerChannel = BassMix.BASS_Mixer_StreamCreate(samplerate, 2, mixerFlags); Console.WriteLine("Player.IsBassInitialized " + Player.IsBassInitialized); Console.WriteLine("Player.IsAsioInitialized " + Player.IsAsioInitialized); Console.WriteLine("Player.IsWasapiInitialized " + Player.IsWasapiInitialized); return(m_mixerChannel); }
/// <summary> /// Called when a stream has been created. This actually starts the playback of the stream. /// </summary> /// <param name="track">The track that is to be played.</param> /// <param name="stream">The BASS.NET stream pointer to play.</param> protected virtual void StreamCreated(IAudioItem track, int stream) { // Init mixer if (_mixer == -1) { _mixer = BassMix.BASS_Mixer_StreamCreate(44100, 6, BASSFlag.BASS_MIXER_END); // Set playback done callback on mixer _channelEndCallback = new SYNCPROC(ChannelEnd); Bass.BASS_ChannelSetSync(_mixer, BASSSync.BASS_SYNC_END | BASSSync.BASS_SYNC_MIXTIME, 0, _channelEndCallback, IntPtr.Zero); } // Load streamin mixer bool ok = BassMix.BASS_Mixer_StreamAddChannel(_mixer, stream, BASSFlag.BASS_STREAM_AUTOFREE | BASSFlag.BASS_MIXER_MATRIX); if (!ok) { Log(Bass.BASS_ErrorGetCode().ToString(), Logger.LogLevel.Error); } // Set matrix SetMatrix(stream); // Remove current channel from mixer if (_currentStream != -1) { BassMix.BASS_Mixer_ChannelRemove(_currentStream); Bass.BASS_StreamFree(_currentStream); } // if (track is IWebcast) { SYNCPROC _mySync = new SYNCPROC(MetaSync); Bass.BASS_ChannelSetSync(_currentStream, BASSSync.BASS_SYNC_META, 0, _mySync, IntPtr.Zero); } // Play it! Bass.BASS_ChannelSetPosition(_mixer, 0); Bass.BASS_Start(); Bass.BASS_ChannelPlay(_mixer, false); // Set current stuff _currentStream = stream; }
public BassWasapiHandler(int device, bool exclusive, bool eventSystem, int freq, int chans, float buffer, float period) { this._device = device; this._exclusive = exclusive; this._eventSystem = eventSystem; if (!BassWasapi.BASS_WASAPI_GetDeviceInfo(device, this._wasapiDeviceInfo)) { throw new ArgumentException("Invalid device: " + Enum.GetName(typeof(BASSError), Bass.Bass.BASS_ErrorGetCode())); } if (exclusive) { this._numchans = chans; } else { this._numchans = this._wasapiDeviceInfo.mixchans; } if (exclusive) { this._samplerate = freq; } else { this._samplerate = this._wasapiDeviceInfo.mixfreq; } this._updatePeriod = period; if (buffer == 0f) { this._bufferLength = ((this._updatePeriod == 0f) ? this._wasapiDeviceInfo.defperiod : this._updatePeriod) * 4f; } else { this._bufferLength = buffer; } if (this.IsInput) { this.UseInput = true; return; } this._internalMixer = BassMix.BASS_Mixer_StreamCreate(this._samplerate, this._numchans, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_AAC_FRAME960); if (this._internalMixer == 0) { throw new NotSupportedException("Internal Mixer: " + Enum.GetName(typeof(BASSError), Bass.Bass.BASS_ErrorGetCode())); } }
/// <summary> /// Initializes the mixer channel. /// </summary> /// <returns>The channel Id of the mixer channel</returns> public static int InitializeOutputChannel(int deviceId) { var currentDeviceId = AudioEngineHelper.GetCurrentDeviceId(); AudioEngineHelper.SetDevice(deviceId); var mixerChannel = BassMix.BASS_Mixer_StreamCreate(DefaultSampleRate, 2, BASSFlag.BASS_SAMPLE_FLOAT); if (mixerChannel == 0) { throw new Exception("Cannot create Bass Mixer."); } AssignChannelToDevice(mixerChannel, deviceId); AudioEngineHelper.SetDevice(currentDeviceId); return(mixerChannel); }
public Module() { Scenes = new BindingList <Scene>(); IsDirty = true; Scenes.ListChanged += new ListChangedEventHandler(Scenes_ListChanged); ModuleMixerChannel = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT); BassMix.BASS_Mixer_ChannelFlags(ModuleMixerChannel, BASSFlag.BASS_MIXER_NORAMPIN, BASSFlag.BASS_MIXER_NORAMPIN); Bass.BASS_ChannelPlay(ModuleMixerChannel, false); reverbChannel = Bass.BASS_ChannelSetFX(ModuleMixerChannel, BASSFXType.BASS_FX_DX8_REVERB, 1000); reverb = new BASS_DX8_REVERB(); reverb.fReverbMix = -96; reverb.fReverbTime = 0; Bass.BASS_FXSetParameters(reverbChannel, reverb); }
public override void Load(string file) { // Dispose on every new load Dispose(false); ready = false; // Create a stream channel from a file (use BASS_STREAM_PRESCAN for mp3?) bassStream = Bass.BASS_StreamCreateFile(file, 0L, 0L, BASSFlag.BASS_STREAM_DECODE); if (bassStream != 0) { var info = Bass.BASS_ChannelGetInfo(bassStream); this.sourceBitDepth = info.Is8bit ? 8 : (info.Is32bit ? 32 : 16); this.sourceSampleRate = info.freq; this.sourceChannels = info.chans; this.sampleRate = info.freq; this.channels = info.chans; duration = (int)Bass.BASS_ChannelBytes2Seconds(bassStream, Bass.BASS_ChannelGetLength(bassStream)); if (this.resample) { this.sampleRate = 11025; this.channels = 1; // Create resample stream. bassMixer = BassMix.BASS_Mixer_StreamCreate(this.sampleRate, this.channels, BASSFlag.BASS_MIXER_END | BASSFlag.BASS_STREAM_DECODE); if (bassMixer == 0) { return; } BassMix.BASS_Mixer_StreamAddChannel(bassMixer, bassStream, 0); } ready = (!info.Is8bit && !info.Is32bit); } }
private void buttonPlaySource_Click(object sender, System.EventArgs e) { Bass.BASS_StreamFree(_streamA); Bass.BASS_StreamFree(_streamB); Bass.BASS_StreamFree(_mixerStream); // mixer setup // now we need some channels to plug them in...create two decoding sources _streamA = Bass.BASS_StreamCreateFile(_fileName, 0, 0, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT); _streamB = Bass.BASS_StreamCreateFile(_fileNameOutput, 0, 0, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT); BASS_CHANNELINFO i = new BASS_CHANNELINFO(); Bass.BASS_ChannelGetInfo(_streamA, i); // this will be the final mixer output stream being played _mixerStream = BassMix.BASS_Mixer_StreamCreate(i.freq, 4, BASSFlag.BASS_DEFAULT); // finally we plug them into the mixer (and upmix it to 4 channels - we assume the source to be stereo) bool okA = BassMix.BASS_Mixer_StreamAddChannel(_mixerStream, _streamA, BASSFlag.BASS_MIXER_MATRIX | BASSFlag.BASS_STREAM_AUTOFREE); bool okB = BassMix.BASS_Mixer_StreamAddChannel(_mixerStream, _streamB, BASSFlag.BASS_STREAM_AUTOFREE); // a matrix for A! float[,] matrixA = new float[4, 2] { // stereo to quad matrix { 1, 0 }, // left front out = left in { 0, 1 }, // right front out = right in { 1, 0 }, // left rear out = left in { 0, 1 } // right rear out = right in }; // apply the matrix to stream A only BassMix.BASS_Mixer_ChannelSetMatrix(_streamA, matrixA); // just so show how to get it back... float[,] matrixGet = new float[4, 2]; BassMix.BASS_Mixer_ChannelGetMatrix(_streamA, matrixGet); // mute streamB at the beginning this.trackBarCrossFader.Value = -100; Bass.BASS_ChannelSetAttribute(_streamB, BASSAttribute.BASS_ATTRIB_VOL, 0f); // and play it... if (Bass.BASS_ChannelPlay(_mixerStream, false)) { this.label1.Text = "Playing! Use the crossfader..."; } }
/// <summary> /// Create a mixer to be used as Output stream. /// We currently need this in case of Up- or Downmixing /// </summary> private void CreateMixer(int channels) { _mixerHandle = BassMix.BASS_Mixer_StreamCreate(_inputStream.SampleRate, channels, MIXER_FLAGS); if (_mixerHandle == BassConstants.BassInvalidHandle) { throw new BassLibraryException("BASS_Mixer_StreamCreate"); } _mixerStream = BassStream.Create(_mixerHandle); // Now Attach the Input Stream to the mixer try { Bass.BASS_ChannelLock(_mixerHandle, true); bool result = BassMix.BASS_Mixer_StreamAddChannel(_mixerHandle, _inputStream.Handle, BASSFlag.BASS_MIXER_NORAMPIN | BASSFlag.BASS_MIXER_BUFFER | BASSFlag.BASS_MIXER_MATRIX | BASSFlag.BASS_MIXER_DOWNMIX | BASSFlag.BASS_STREAM_AUTOFREE ); if (!result) { throw new BassLibraryException("BASS_UpDownMix_StreamAddChannel"); } } finally { Bass.BASS_ChannelLock(_mixerHandle, false); } if (_mixingMatrix != null) { bool result = BassMix.BASS_Mixer_ChannelSetMatrix(_inputStream.Handle, _mixingMatrix); if (!result) { throw new BassLibraryException("BASS_UpDownMix_SetMixingMatrix"); } } }
public static void Play(string file, bool loadOnly) { Stop(); baseStreamHandle = Bass.BASS_StreamCreateFile(file, 0, 0, BASSFlag.BASS_STREAM_DECODE); BASS_CHANNELINFO info = Bass.BASS_ChannelGetInfo(baseStreamHandle); mixStreamHandle = BassMix.BASS_Mixer_StreamCreate(info.freq, info.chans, BASSFlag.BASS_STREAM_DECODE); BassMix.BASS_Mixer_StreamAddChannel(mixStreamHandle, baseStreamHandle, BASSFlag.BASS_MIXER_MATRIX); streamHandle = BassFx.BASS_FX_TempoCreate(mixStreamHandle, BASSFlag.BASS_FX_FREESOURCE); Mono = mono; Speed = speed; if (!loadOnly) { Bass.BASS_ChannelPlay(streamHandle, false); } BASSError er = Bass.BASS_ErrorGetCode(); syncProc = new SYNCPROC(AudioEnded); Bass.BASS_ChannelSetSync(streamHandle, BASSSync.BASS_SYNC_END, 0, syncProc, IntPtr.Zero); Playing = !loadOnly; FileLoaded = true; }
public void Play_With_Buildup() { Stop(); if (InitBass(HZ)) { Channel = BassMix.BASS_Mixer_StreamCreate(HZ, 2, BASSFlag.BASS_MIXER_END); point_B = GCHandle.Alloc(build_mem, GCHandleType.Pinned); point_L = GCHandle.Alloc(loop_mem, GCHandleType.Pinned); Stream_B = Bass.BASS_StreamCreateFile(point_B.AddrOfPinnedObject(), 0, build_mem.LongLength, BASSFlag.BASS_STREAM_DECODE); build_len = Bass.BASS_ChannelGetLength(Stream_B, BASSMode.BASS_POS_BYTES); Stream_L = Bass.BASS_StreamCreateFile(point_L.AddrOfPinnedObject(), 0, loop_mem.LongLength, BASSFlag.BASS_STREAM_DECODE); loop_len = Bass.BASS_ChannelGetLength(Stream_L); BassMix.BASS_Mixer_StreamAddChannel(Channel, Stream_B, BASSFlag.BASS_DEFAULT); BassMix.BASS_Mixer_StreamAddChannelEx(Channel, Stream_L, BASSFlag.BASS_MIXER_NORAMPIN, build_len, 0); _loopSync = BassMix.BASS_Mixer_ChannelSetSync(Stream_L, BASSSync.BASS_SYNC_POS | BASSSync.BASS_SYNC_MIXTIME, loop_len, _loopSyncCallback, new IntPtr(1)); } }
public override void Initialize(int deviceid) { Bass.BASS_SetDevice(deviceid); BASSFlag flag = BASSFlag.BASS_DEFAULT | BASSFlag.BASS_SAMPLE_FLOAT; if (this.IsDecoding) { flag = flag | BASSFlag.BASS_STREAM_DECODE; } int handle = BassMix.BASS_Mixer_StreamCreate(44100, this.NumChans, flag); this.BassHandle = handle; //Add the channel list in bass now foreach (ChannelInfo info in this.Streams) { if (!info.BassHandle.HasValue) { info.Initialize(deviceid); } else { if (info.BassHandle.Value == 0) { info.Initialize(deviceid); } } BassMix.BASS_Mixer_StreamAddChannel(this.BassHandle.Value, info.BassHandle.Value, BASSFlag.BASS_MIXER_MATRIX | BASSFlag.BASS_MIXER_BUFFER); info.Play = info.Play; } this.Play = this.Play; //Bass.BASS_ChannelPlay(this.BassHandle.Value, false); this.OnInitialize(); }
public void startDSP() { // Try to start the DSP // possible errors may include faulty audio drives/hardware, or restricted hardware access // or maybe the library just isn't there, or isn't working try { _isItLoaded = Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero); } catch (Exception E) { Console.WriteLine(E.ToString()); } if (running()) { // the basic functionality here for construction of the mixer // try to use floating point sampling (if hardware can even do it) _mixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_SAMPLE_FLOAT); _vis = new Visuals(); Bass.BASS_ChannelPlay(_mixer, false); } }
private void Setup() { if (!Bassh.BASS_Init(-1, sampleRate.Value, BASSInit.BASS_DEVICE_LATENCY | BASSInit.BASS_DEVICE_FREQ, IntPtr.Zero)) { throw new InvalidOperationException("Could not initialize BASS"); } Bassh.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATETHREADS, 4); Bassh.BASS_SetConfig(BASSConfig.BASS_CONFIG_BUFFER, bufferSize.Value); Bassh.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATEPERIOD, bufferSize.Value / 10); Trace.WriteLine(Bassh.BASS_GetInfo()); var plugins = Bassh.BASS_PluginLoadDirectory(Environment.CurrentDirectory); mixerHandle = BassMix.BASS_Mixer_StreamCreate(sampleRate.Value, 2, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_MIXER_NONSTOP); Bassh.BASS_ChannelPlay(mixerHandle, true); if (null == plugins) { return; } foreach (var plugin in plugins) { pluginHandles.Add(plugin.Key); logger.Log(LoggingType.Information, this, string.Format("Plugin Loaded: {0}", plugin.Value)); } }
// メソッド public CSoundDeviceASIO(long n希望バッファサイズms, int _nASIODevice) { // 初期化。 Trace.TraceInformation("BASS (ASIO) の初期化を開始します。"); this.e出力デバイス = ESoundDeviceType.Unknown; this.n実出力遅延ms = 0; this.n経過時間ms = 0; this.n経過時間を更新したシステム時刻ms = CTimer.n未使用; this.tmシステムタイマ = new CTimer(); this.nASIODevice = _nASIODevice; #region [ BASS registration ] // BASS.NET ユーザ登録(BASSスプラッシュが非表示になる)。 BassNet.Registration("*****@*****.**", "2X9181017152222"); #endregion #region [ BASS Version Check ] // BASS のバージョンチェック。 int nBASSVersion = Utils.HighWord(Bass.BASS_GetVersion()); if (nBASSVersion != Bass.BASSVERSION) { throw new DllNotFoundException(string.Format("bass.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSVersion, Bass.BASSVERSION)); } int nBASSMixVersion = Utils.HighWord(BassMix.BASS_Mixer_GetVersion()); if (nBASSMixVersion != BassMix.BASSMIXVERSION) { throw new DllNotFoundException(string.Format("bassmix.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSMixVersion, BassMix.BASSMIXVERSION)); } int nBASSASIO = Utils.HighWord(BassAsio.BASS_ASIO_GetVersion()); if (nBASSASIO != BassAsio.BASSASIOVERSION) { throw new DllNotFoundException(string.Format("bassasio.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSASIO, BassAsio.BASSASIOVERSION)); } #endregion // BASS の設定。 this.bIsBASSFree = true; if (!Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0)) // 0:BASSストリームの自動更新を行わない。 { Trace.TraceWarning($"BASS_SetConfig({nameof(BASSConfig.BASS_CONFIG_UPDATEPERIOD)}) に失敗しました。[{Bass.BASS_ErrorGetCode()}]"); } if (!Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATETHREADS, 0)) // 0:BASSストリームの自動更新を行わない。 { Trace.TraceWarning($"BASS_SetConfig({nameof(BASSConfig.BASS_CONFIG_UPDATETHREADS)}) に失敗しました。[{Bass.BASS_ErrorGetCode()}]"); } // BASS の初期化。 int nデバイス = 0; // 0:"no device" … BASS からはデバイスへアクセスさせない。アクセスは BASSASIO アドオンから行う。 int n周波数 = 44100; // 仮決め。最終的な周波数はデバイス(≠ドライバ)が決める。 if (!Bass.BASS_Init(nデバイス, n周波数, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero)) { throw new Exception(string.Format("BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.BASS_ErrorGetCode().ToString())); } Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_CURVE_VOL, true); //Debug.WriteLine( "BASS_Init()完了。" ); #region [ デバッグ用: ASIOデバイスのenumerateと、ログ出力 ] // CEnumerateAllAsioDevices.GetAllASIODevices(); //Debug.WriteLine( "BassAsio.BASS_ASIO_GetDeviceInfo():" ); // int a, count = 0; // BASS_ASIO_DEVICEINFO asioDevInfo; // for ( a = 0; ( asioDevInfo = BassAsio.BASS_ASIO_GetDeviceInfo( a ) ) != null; a++ ) // { // Trace.TraceInformation( "ASIO Device {0}: {1}, driver={2}", a, asioDevInfo.name, asioDevInfo.driver ); // count++; // count it // } #endregion // BASS ASIO の初期化。 BASS_ASIO_INFO asioInfo = null; if (BassAsio.BASS_ASIO_Init(nASIODevice, BASSASIOInit.BASS_ASIO_THREAD)) // 専用スレッドにて起動 { #region [ ASIO の初期化に成功。] //----------------- this.e出力デバイス = ESoundDeviceType.ASIO; asioInfo = BassAsio.BASS_ASIO_GetInfo(); this.n出力チャンネル数 = asioInfo.outputs; this.db周波数 = BassAsio.BASS_ASIO_GetRate(); this.fmtASIOデバイスフォーマット = BassAsio.BASS_ASIO_ChannelGetFormat(false, 0); Trace.TraceInformation("BASS を初期化しました。(ASIO, デバイス:\"{0}\", 入力{1}, 出力{2}, {3}Hz, バッファ{4}~{6}sample ({5:0.###}~{7:0.###}ms), デバイスフォーマット:{8})", asioInfo.name, asioInfo.inputs, asioInfo.outputs, this.db周波数.ToString("0.###"), asioInfo.bufmin, asioInfo.bufmin * 1000 / this.db周波数, asioInfo.bufmax, asioInfo.bufmax * 1000 / this.db周波数, this.fmtASIOデバイスフォーマット.ToString() ); this.bIsBASSFree = false; #region [ debug: channel format ] //BASS_ASIO_CHANNELINFO chinfo = new BASS_ASIO_CHANNELINFO(); //int chan = 0; //while ( true ) //{ // if ( !BassAsio.BASS_ASIO_ChannelGetInfo( false, chan, chinfo ) ) // break; // Debug.WriteLine( "Ch=" + chan + ": " + chinfo.name.ToString() + ", " + chinfo.group.ToString() + ", " + chinfo.format.ToString() ); // chan++; //} #endregion //----------------- #endregion } else { #region [ ASIO の初期化に失敗。] //----------------- BASSError errcode = Bass.BASS_ErrorGetCode(); string errmes = errcode.ToString(); if (errcode == BASSError.BASS_OK) { errmes = "BASS_OK; The device may be dissconnected"; } Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("BASS (ASIO) の初期化に失敗しました。(BASS_ASIO_Init)[{0}]", errmes)); //----------------- #endregion } // ASIO 出力チャンネルの初期化。 this.tAsioProc = new ASIOPROC(this.tAsio処理); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。 if (!BassAsio.BASS_ASIO_ChannelEnable(false, 0, this.tAsioProc, IntPtr.Zero)) // 出力チャンネル0 の有効化。 { #region [ ASIO 出力チャンネルの初期化に失敗。] //----------------- BassAsio.BASS_ASIO_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("Failed BASS_ASIO_ChannelEnable() [{0}]", BassAsio.BASS_ASIO_ErrorGetCode().ToString())); //----------------- #endregion } for (int i = 1; i < this.n出力チャンネル数; i++) // 出力チャネルを全てチャネル0とグループ化する。 { // チャネル1だけを0とグループ化すると、3ch以上の出力をサポートしたカードでの動作がおかしくなる if (!BassAsio.BASS_ASIO_ChannelJoin(false, i, 0)) { #region [ 初期化に失敗。] //----------------- BassAsio.BASS_ASIO_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("Failed BASS_ASIO_ChannelJoin({1}) [{0}]", BassAsio.BASS_ASIO_ErrorGetCode().ToString(), i)); //----------------- #endregion } } if (!BassAsio.BASS_ASIO_ChannelSetFormat(false, 0, this.fmtASIOチャンネルフォーマット)) // 出力チャンネル0のフォーマット { #region [ ASIO 出力チャンネルの初期化に失敗。] //----------------- BassAsio.BASS_ASIO_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("Failed BASS_ASIO_ChannelSetFormat() [{0}]", BassAsio.BASS_ASIO_ErrorGetCode().ToString())); //----------------- #endregion } // ASIO 出力と同じフォーマットを持つ BASS ミキサーを作成。 var flag = BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_STREAM_DECODE; // デコードのみ=発声しない。ASIO に出力されるだけ。 if (this.fmtASIOデバイスフォーマット == BASSASIOFormat.BASS_ASIO_FORMAT_FLOAT) { flag |= BASSFlag.BASS_SAMPLE_FLOAT; } this.hMixer = BassMix.BASS_Mixer_StreamCreate((int)this.db周波数, this.n出力チャンネル数, flag); if (this.hMixer == 0) { BASSError err = Bass.BASS_ErrorGetCode(); BassAsio.BASS_ASIO_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("BASSミキサ(mixing)の作成に失敗しました。[{0}]", err)); } // BASS ミキサーの1秒あたりのバイト数を算出。 var mixerInfo = Bass.BASS_ChannelGetInfo(this.hMixer); int nサンプルサイズbyte = 0; switch (this.fmtASIOチャンネルフォーマット) { case BASSASIOFormat.BASS_ASIO_FORMAT_16BIT: nサンプルサイズbyte = 2; break; case BASSASIOFormat.BASS_ASIO_FORMAT_24BIT: nサンプルサイズbyte = 3; break; case BASSASIOFormat.BASS_ASIO_FORMAT_32BIT: nサンプルサイズbyte = 4; break; case BASSASIOFormat.BASS_ASIO_FORMAT_FLOAT: nサンプルサイズbyte = 4; break; } //long nミキサーの1サンプルあたりのバイト数 = /*mixerInfo.chans*/ 2 * nサンプルサイズbyte; long nミキサーの1サンプルあたりのバイト数 = mixerInfo.chans * nサンプルサイズbyte; this.nミキサーの1秒あたりのバイト数 = nミキサーの1サンプルあたりのバイト数 * mixerInfo.freq; // 単純に、hMixerの音量をMasterVolumeとして制御しても、 // ChannelGetData()の内容には反映されない。 // そのため、もう一段mixerを噛ませて、一段先のmixerからChannelGetData()することで、 // hMixerの音量制御を反映させる。 this.hMixer_DeviceOut = BassMix.BASS_Mixer_StreamCreate( (int)this.db周波数, this.n出力チャンネル数, flag); if (this.hMixer_DeviceOut == 0) { BASSError errcode = Bass.BASS_ErrorGetCode(); BassAsio.BASS_ASIO_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode)); } { bool b1 = BassMix.BASS_Mixer_StreamAddChannel(this.hMixer_DeviceOut, this.hMixer, BASSFlag.BASS_DEFAULT); if (!b1) { BASSError errcode = Bass.BASS_ErrorGetCode(); BassAsio.BASS_ASIO_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode)); } ; } // 出力を開始。 this.nバッファサイズsample = (int)(n希望バッファサイズms * this.db周波数 / 1000.0); //this.nバッファサイズsample = (int) nバッファサイズbyte; if (!BassAsio.BASS_ASIO_Start(this.nバッファサイズsample)) // 範囲外の値を指定した場合は自動的にデフォルト値に設定される。 { BASSError err = BassAsio.BASS_ASIO_ErrorGetCode(); BassAsio.BASS_ASIO_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception("ASIO デバイス出力開始に失敗しました。" + err.ToString()); } else { int n遅延sample = BassAsio.BASS_ASIO_GetLatency(false); // この関数は BASS_ASIO_Start() 後にしか呼び出せない。 int n希望遅延sample = (int)(n希望バッファサイズms * this.db周波数 / 1000.0); this.n実バッファサイズms = this.n実出力遅延ms = (long)(n遅延sample * 1000.0f / this.db周波数); Trace.TraceInformation("ASIO デバイス出力開始:バッファ{0}sample(希望{1}) [{2}ms(希望{3}ms)]", n遅延sample, n希望遅延sample, this.n実出力遅延ms, n希望バッファサイズms); } }
/// <summary> /// Create a mixer using the stream attributes /// </summary> /// <param name="stream"></param> /// <returns></returns> 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); _upmixing = true; } 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"); 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); bool wasApiExclusiveSupported = true; // Check if we have an uneven number of channels var chkChannels = outputChannels % 2; if (chkChannels == 1) { Log.Warn("BASS: Found uneven number of channels {0}. increase output channels.", outputChannels); outputChannels++; // increase the number of output channels wasApiExclusiveSupported = false; // And indicate that we need a new mixer } // Handle the special cases of 3.0, 4.0 and 5.0 files being played on a 5.1 or 6.1 device if (outputChannels == 3) // a 3.0 file { Log.Info("BASS: Found a 3 channel file. Set upmixing with LFE, LR, RR set to silent"); _mixingMatrix = CreateThreeDotZeroUpMixMatrix(); outputChannels = _bassPlayer.DeviceChannels; // WASAPI device should be initialised with all channels active wasApiExclusiveSupported = false; // And indicate that we need a new mixer } else if (outputChannels == 4) // a 4.0 file { Log.Info("BASS: Found a 4 channel file. Set upmixing with Center and LFE set to silent"); _mixingMatrix = CreateFourDotZeroUpMixMatrix(); outputChannels = _bassPlayer.DeviceChannels; // WASAPI device should be initialised with all channels active wasApiExclusiveSupported = false; // And indicate that we need a new mixer } else if (outputChannels == 5) // a 5.0 file { Log.Info("BASS: Found a 5 channel file. Set upmixing with LFE set to silent"); _mixingMatrix = CreateFiveDotZeroUpMixMatrix(); outputChannels = _bassPlayer.DeviceChannels; // WASAPI device should be initialised with all channels active wasApiExclusiveSupported = false; // And indicate that we need a new mixer } // 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, outputChannels, 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; } Log.Debug("BASS: Try to init WASAPI with a Frequency of {0} and {1} channels", stream.ChannelInfo.freq, outputChannels); if (BassWasapi.BASS_WASAPI_Init(_bassPlayer.DeviceNumber, stream.ChannelInfo.freq, outputChannels, initFlags | BASSWASAPIInit.BASS_WASAPI_BUFFER, Convert.ToSingle(Config.BufferingMs / 1000.0), 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); }
private void ProcessStreamData(byte[] buffer, int offset, int length) { if (length < 1) { return; } // Write compressed audio data to Circulairbuffer byte[] data = new byte[length]; Buffer.BlockCopy(buffer, offset, data, 0, length); lock (lockObject) { cbbChunkAudio.Write(buffer, offset, length); } // If basshandle wasn't opened then open it now (when there is enough data. Min 4010 bytes) if (inputHandle == 0 && cbbChunkAudio.UsedBytes >= 8000) { // bass needs for mp3 atleast 4000 bytes before is can play inputHandle = Bass.BASS_StreamCreateFileUser(BASSStreamSystem.STREAMFILE_BUFFERPUSH, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT, bassFileProcs, GCHandle.ToIntPtr((GCHandle)gcHandle)); Bass.BASS_ChannelSetSync(inputHandle, BASSSync.BASS_SYNC_STALL, 0, bassStalledSync, GCHandle.ToIntPtr((GCHandle)gcHandle)); Bass.BASS_ChannelSetSync(inputHandle, BASSSync.BASS_SYNC_END, 0, bassEndSync, GCHandle.ToIntPtr((GCHandle)gcHandle)); mixerHandle = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT); BassMix.BASS_Mixer_StreamAddChannel(mixerHandle, inputHandle, BASSFlag.BASS_MIXER_FILTER | BASSFlag.BASS_MIXER_DOWNMIX); Bass.BASS_ChannelPlay(inputHandle, false); Bass.BASS_ChannelPlay(mixerHandle, false); return; } // push new audiodata when available (and basstream is opened) if (inputHandle != 0) { // voed bass met audio data zodat deze het naar pcm data kan decompressen long bassBufLen = Bass.BASS_StreamGetFilePosition(inputHandle, BASSStreamFilePosition.BASS_FILEPOS_END); long bassBufPos = Bass.BASS_StreamGetFilePosition(inputHandle, BASSStreamFilePosition.BASS_FILEPOS_BUFFER); int todo = Convert.ToInt32(bassBufLen - bassBufPos); if (todo > 0) { int count = todo; int writeBytes = 0; while (!cbbChunkAudio.IsEmpty && todo > 0 && writeBytes > -1) { if (count > 16384) { count = 16384; } byte[] tmpBuffer = new byte[count]; lock (lockObject) { count = cbbChunkAudio.Read(tmpBuffer, count); } if (count > 0) { writeBytes = Bass.BASS_StreamPutFileData(inputHandle, tmpBuffer, count); todo -= writeBytes; } } //while audio buffer not empty } ProcessDecompressedData(); } }
public int CreateMixerStream(int sampleRate, int channels, BASSFlag flags) { return(BassMix.BASS_Mixer_StreamCreate(sampleRate, channels, flags)); }
public override void SetInputStream(BassStream stream, bool passThrough) { if (_deviceState != DeviceState.Stopped) { throw new BassPlayerException("Device state is not 'DeviceState.Stopped'"); } _inputStream = stream; _flags = BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_BUFFER; // If Exclusive mode is used, check, if that would be supported, otherwise init in shared mode bool isExclusive = Controller.GetSettings().WASAPIExclusiveMode; if (isExclusive) { _flags |= BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE; BASSWASAPIFormat wasapiFormat = BassWasapi.BASS_WASAPI_CheckFormat(_deviceNo, _inputStream.SampleRate, _inputStream.Channels, BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE); if (wasapiFormat == BASSWASAPIFormat.BASS_WASAPI_FORMAT_UNKNOWN) { Log.Info("BASS: WASAPI exclusive mode not directly supported for samplerate of {0} and {1} channels", _inputStream.SampleRate, _inputStream.Channels); isExclusive = false; } } retry: if (!isExclusive) { Log.Debug("BASS: Init WASAPI shared mode with Event driven system enabled."); _flags &= ~BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE; _flags |= BASSWASAPIInit.BASS_WASAPI_SHARED | BASSWASAPIInit.BASS_WASAPI_EVENT; } Log.Debug("BASS: Try to init WASAPI with a samplerate of {0} and {1} channels", _inputStream.SampleRate, _inputStream.Channels); bool result = BassWasapi.BASS_WASAPI_Init(_deviceNo, _inputStream.SampleRate, _inputStream.Channels, _flags, 0.5f, 0f, _streamWriteProcDelegate, IntPtr.Zero); BASSError?bassInitErrorCode = result ? null : new BASSError?(Bass.BASS_ErrorGetCode()); if (bassInitErrorCode.HasValue) { if (bassInitErrorCode.Value == BASSError.BASS_ERROR_ALREADY) { if (!BassWasapi.BASS_WASAPI_SetDevice(_deviceNo)) { throw new BassLibraryException("BASS_WASAPI_SetDevice"); } } else if (isExclusive) { // Allow one retry in shared mode Log.Warn("BASS: Failed to initialize WASAPI exclusive mode for samplerate of {0} and {1} channels. Trying fallback to shared mode.", _inputStream.SampleRate, _inputStream.Channels); isExclusive = false; goto retry; } else { throw new BassLibraryException("BASS_WASAPI_Init"); } } // If the GetDeviceNo() method returned BassConstants.BassDefaultDevice, we must request the actual device number // of the choosen default device _deviceNo = BassWasapi.BASS_WASAPI_GetDevice(); CollectDeviceInfo(_deviceNo); 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"); // For shared mode we require a mixer to change the sampling rates of input stream to device output stream. if (!wasapiInfo.IsExclusive) { // Recreate Mixer with new value Log.Debug("BASS: Creating new {0} channel mixer for frequency {1}", wasapiInfo.chans, wasapiInfo.freq); _mixerHandle = BassMix.BASS_Mixer_StreamCreate(wasapiInfo.freq, wasapiInfo.chans, MIXER_FLAGS); if (_mixerHandle == BassConstants.BassInvalidHandle) { throw new BassLibraryException("BASS_Mixer_StreamCreate"); } _mixer = BassStream.Create(_mixerHandle); AttachStream(); } int ms = Convert.ToInt32(Controller.GetSettings().DirectSoundBufferSize.TotalMilliseconds); if (!Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_BUFFER, ms)) { throw new BassLibraryException("BASS_SetConfig"); } // Enable update thread while the output device is active if (!Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATEPERIOD, ms / 4)) { throw new BassLibraryException("BASS_SetConfig"); } if (passThrough) { _fader = new BassStreamFader(_inputStream, Controller.GetSettings().FadeDuration); } ResetState(); }
/// <summary> /// Read mono from file /// </summary> /// <param name = "filename">Name of the file</param> /// <param name = "samplerate">Sample rate</param> /// <param name = "milliseconds">milliseconds to read</param> /// <param name = "startmillisecond">Start millisecond</param> /// <returns>Array of samples</returns> public float[] ReadMonoFromFile(string filename, int samplerate, int milliseconds, int startmillisecond) { int totalmilliseconds = milliseconds <= 0 ? Int32.MaxValue : milliseconds + startmillisecond; float[] data = null; //create streams for re-sampling int stream = Un4seen.Bass.Bass.BASS_StreamCreateFile(filename, 0, 0, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_MONO | BASSFlag.BASS_SAMPLE_FLOAT); //Decode the stream if (stream == 0) { throw new Exception(Un4seen.Bass.Bass.BASS_ErrorGetCode().ToString()); } int mixerStream = BassMix.BASS_Mixer_StreamCreate(samplerate, 1, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_MONO | BASSFlag.BASS_SAMPLE_FLOAT); if (mixerStream == 0) { throw new Exception(Un4seen.Bass.Bass.BASS_ErrorGetCode().ToString()); } if (BassMix.BASS_Mixer_StreamAddChannel(mixerStream, stream, BASSFlag.BASS_MIXER_FILTER)) { const int bufferSize = 5512 * 10 * 4; /*read ten seconds at each iteration*/ float[] buffer = new float[bufferSize]; List <float[]> chunks = new List <float[]>(); int size = 0; while ((float)(size) / samplerate * 1000 < totalmilliseconds) { //get re-sampled/mono data int bytesRead = Un4seen.Bass.Bass.BASS_ChannelGetData(mixerStream, buffer, bufferSize); if (bytesRead == 0) { break; } float[] chunk = new float[bytesRead / 4]; //each float contains 4 bytes Array.Copy(buffer, chunk, bytesRead / 4); chunks.Add(chunk); size += bytesRead / 4; //size of the data } if ((float)(size) / samplerate * 1000 < (milliseconds + startmillisecond)) { return(null); /*not enough samples to return the requested data*/ } int start = (int)((float)startmillisecond * samplerate / 1000); int end = (milliseconds <= 0) ? size : (int)((float)(startmillisecond + milliseconds) * samplerate / 1000); data = new float[size]; int index = 0; /*Concatenate*/ foreach (float[] chunk in chunks) { Array.Copy(chunk, 0, data, index, chunk.Length); index += chunk.Length; } /*Select specific part of the song*/ if (start != 0 || end != size) { float[] temp = new float[end - start]; Array.Copy(data, start, temp, 0, end - start); data = temp; } } else { throw new Exception(Un4seen.Bass.Bass.BASS_ErrorGetCode().ToString()); } return(data); }