/// <summary> /// Attach a stream to the Mixer /// </summary> /// <returns></returns> public bool AttachStream() { try { Bass.BASS_ChannelLock(_mixerHandle, true); RegisterStreamFreedEvent(_inputStream); 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_Mixer_StreamAddChannel"); } return(true); } finally { Bass.BASS_ChannelLock(_mixerHandle, false); } }
private void buttonAddFile_Click(object sender, EventArgs e) { if (DialogResult.OK == openFileDialog.ShowDialog(this)) { if (File.Exists(openFileDialog.FileName)) { lock (listBoxPlaylist) { Track track = new Track(openFileDialog.FileName); listBoxPlaylist.Items.Add(track); // in the demo we already add each new track to the mixer // this is in real life not the best place to do so (especially with larger playlists) // but for the demo it is okay ;-) // add the new track to the mixer (in PAUSED mode!) BassMix.BASS_Mixer_StreamAddChannel(_mixer, track.Channel, BASSFlag.BASS_MIXER_PAUSE | BASSFlag.BASS_MIXER_DOWNMIX | BASSFlag.BASS_STREAM_AUTOFREE); // an BASS_SYNC_END is used to trigger the next track in the playlist (if no POS sync was set) track.TrackSync = new SYNCPROC(OnTrackSync); BassMix.BASS_Mixer_ChannelSetSync(track.Channel, BASSSync.BASS_SYNC_END, 0L, track.TrackSync, new IntPtr(0)); } if (_currentTrack == null) { PlayNextTrack(); } } } }
/// <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> /// Adds to the mixer channel, and sets the sync points. /// </summary> /// <param name="sample">The sample to sync.</param> private void AddSampleToMixer(Sample sample) { if (sample == null) { return; } Debug.Print("Add sample to mixer " + sample.Description); // load audio data if not loaded if (sample.Channel == int.MinValue) { LoadSampleAudioData(sample); } //if (sample != this.PreviousSample && sample != this.CurrentSample) //{ // add the new sample to the mixer (in paused mode) //BassMix.BASS_Mixer_StreamAddChannel(_mixerChannel, sample.Channel, BASSFlag.BASS_MIXER_PAUSE | BASSFlag.BASS_MIXER_DOWNMIX | BASSFlag.BASS_STREAM_AUTOFREE); BassMix.BASS_Mixer_StreamAddChannel(_sampleMixerChannel, sample.Channel, BASSFlag.BASS_MIXER_PAUSE | BASSFlag.BASS_MIXER_DOWNMIX); //// set sample sync event //sample.SampleSync = new SYNCPROC(OnSampleSync); //// set replay gain //BassHelper.SetSampleReplayGain(sample.Channel, sample.Gain); //} }
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(); }
public void LoadSample(Sample sample) { if (sample.FileName == null) { return; } if (sample.FileName.EndsWith(".wma")) { sample.Channel = BassWma.BASS_WMA_StreamCreateFile(sample.FileName, 0L, 0L, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT); } else { sample.Channel = Bass.BASS_StreamCreateFile(sample.FileName, 0L, 0L, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT); } BassMix.BASS_Mixer_StreamAddChannel(SoundEffectMixerChannel, sample.Channel, BASSFlag.BASS_MIXER_PAUSE); Bass.BASS_ChannelSetSync(sample.Channel, BASSSync.BASS_SYNC_END, 0, endSync, IntPtr.Zero); //sample.Weight = 1; if (CurrentSample == null) { CurrentSample = sample; } SetLoop(); }
/// <summary> /// Attach a stream to the Mixer /// </summary> /// <param name="stream"></param> /// <returns></returns> public bool AttachStream(MusicStream stream) { Bass.BASS_ChannelLock(_mixer, true); // Set SynyPos at end of stream SetSyncPos(stream, 0.0); bool result = BassMix.BASS_Mixer_StreamAddChannel(_mixer, stream.BassStream, BASSFlag.BASS_MIXER_NORAMPIN | BASSFlag.BASS_MIXER_BUFFER | BASSFlag.BASS_MIXER_MATRIX | BASSFlag.BASS_MIXER_DOWNMIX | BASSFlag.BASS_STREAM_AUTOFREE); if (!result) { Log.Error("BASS: Error attaching stream to mixer. {0}", Bass.BASS_ErrorGetCode()); } Bass.BASS_ChannelLock(_mixer, false); if (result && _mixingMatrix != null) { Log.Debug("BASS: Setting mixing matrix..."); result = BassMix.BASS_Mixer_ChannelSetMatrix(stream.BassStream, _mixingMatrix); if (!result) { Log.Error("BASS: Error attaching Mixing Matrix. {0}", Bass.BASS_ErrorGetCode()); } } return(result); }
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); }
public void AttachChannel(ChannelInfo info) { if (info is InputChannelInfo) { InputChannelInfo iinfo = (InputChannelInfo)info; if (this.BassHandle.HasValue) { BassMix.BASS_Mixer_StreamAddChannel(this.BassHandle.Value, iinfo.Handler.OutputChannel, BASSFlag.BASS_MIXER_MATRIX | BASSFlag.BASS_MIXER_BUFFER); } } else { if (!info.BassHandle.HasValue) { //Initialize to no sound as it's decoding anyway info.Initialize(0); } this.streams.Add(info); if (this.BassHandle.HasValue) { BassMix.BASS_Mixer_StreamAddChannel(this.BassHandle.Value, info.BassHandle.Value, BASSFlag.BASS_MIXER_MATRIX | BASSFlag.BASS_MIXER_BUFFER); } //Simple trick to refresh play status now it's attached } info.Play = info.Play; }
public void StreamAddChannel(int channel, SYNCPROC trackSync) { //BassMix.BASS_Mixer_StreamAddChannel(Player.Mixer, channel, BASSFlag.BASS_MIXER_PAUSE | BASSFlag.BASS_STREAM_AUTOFREE | BASSFlag.BASS_MIXER_DOWNMIX); BassMix.BASS_Mixer_StreamAddChannel(Player.Mixer, channel, BASSFlag.BASS_MIXER_PAUSE | BASSFlag.BASS_MIXER_DOWNMIX | BASSFlag.BASS_STREAM_AUTOFREE); // an BASS_SYNC_END is used to trigger the next track in the playlist (if no POS sync was set) BassMix.BASS_Mixer_ChannelSetSync(channel, BASSSync.BASS_SYNC_END, 0L, trackSync, new IntPtr(1)); }
void Scenes_ListChanged(object sender, ListChangedEventArgs e) { if (e.ListChangedType == ListChangedType.ItemAdded) { Scenes[e.NewIndex].StoppingOthers += new EventHandler(Module_StoppingOthers); BassMix.BASS_Mixer_StreamAddChannel(ModuleMixerChannel, Scenes[e.NewIndex].SceneMixerChannel, BASSFlag.BASS_DEFAULT); } }
void SoundEffects_ListChanged(object sender, ListChangedEventArgs e) { Stop(false); if (e.ListChangedType == ListChangedType.ItemAdded) { BassMix.BASS_Mixer_StreamAddChannel(SceneMixerChannel, SoundEffects[e.NewIndex].SoundEffectMixerChannel, BASSFlag.BASS_DEFAULT); } }
public bool AddMixerChannel(int source) { int mixer = this.StreamMixer; this.StreamMixer = mixer; this.StreamPlugged = source; return(BassMix.BASS_Mixer_StreamAddChannel(mixer, source, BASSFlag.BASS_MIXER_NORAMPIN)); }
/// <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 bool loadDeckB(string songName) { if (running()) { if (!songName.Equals(string.Empty)) { _songB = songName; _deckB = Bass.BASS_StreamCreateFile(songName, 0, 0, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT); _bRunning = false; // definitely not playing bool b = BassMix.BASS_Mixer_StreamAddChannel(_mixer, _deckB, BASSFlag.BASS_DEFAULT); BassMix.BASS_Mixer_ChannelPause(_deckB); // pause as soon as it loads return(b); } } return(false); }
/// <summary> /// Creates the channel. /// </summary> /// <param name="file">The file.</param> /// <returns></returns> public ITrack CreateChannel(string file) { var channelHandle = Bassh.BASS_StreamCreateFile(file, 0, 0, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE); Bassh.BASS_ChannelSetAttribute(channelHandle, BASSAttribute.BASS_ATTRIB_SRC, 2); Debug.WriteLine(Bassh.BASS_ChannelGetInfo(channelHandle)); if (0 == channelHandle) { throw new InvalidOperationException("Unable to create stream"); } if (!BassMix.BASS_Mixer_StreamAddChannel(mixerHandle, channelHandle, BASSFlag.BASS_MIXER_PAUSE | BASSFlag.BASS_MIXER_BUFFER | BASSFlag.BASS_MIXER_NORAMPIN)) { Trace.WriteLine(Bassh.BASS_ErrorGetCode()); throw new InvalidOperationException("Unable to add channel to mixer."); } return(new BassTrack(channelHandle, mixerHandle, file)); }
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); }
/// <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 bool AddOutputSource(int channel, BASSFlag flags) { BASS_CHANNELINFO bass_CHANNELINFO = Bass.Bass.BASS_ChannelGetInfo(channel); if (bass_CHANNELINFO == null) { return(false); } if (!bass_CHANNELINFO.IsDecodingChannel && bass_CHANNELINFO.ctype != BASSChannelType.BASS_CTYPE_RECORD) { return(false); } if (flags < BASSFlag.BASS_SPEAKER_FRONT) { flags |= BASSFlag.BASS_WV_STEREO; } return(BassMix.BASS_Mixer_StreamAddChannel(this._internalMixer, channel, flags)); }
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..."; } }
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; }
/// <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 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(); }
/// <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, MixerChannel mixerChannel) { if (audioStream == null || !audioStream.IsAudioLoaded()) { throw new Exception("Audio file null or not audio not loaded"); } if (mixerChannel.ChannelId == int.MinValue) { throw new Exception("Mixer channel not initialized"); } // DebugHelper.WriteLine($"AddToMixer {audioStream.Description} {mixerChannel} {audioStream.Channel}..."); BassMix.BASS_Mixer_StreamAddChannel(mixerChannel.ChannelId, audioStream.ChannelId, BASSFlag.BASS_MIXER_PAUSE | BASSFlag.BASS_MIXER_DOWNMIX | BASSFlag.BASS_MIXER_NORAMPIN | BASSFlag.BASS_MUSIC_AUTOFREE); Thread.Sleep(1); audioStream.MixerChannelId = mixerChannel.ChannelId; // DebugHelper.WriteLine("done"); }
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(); } }
/// <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); }
public bool CombineMixerStreams(int mixerStream, int stream, BASSFlag flags) { return(BassMix.BASS_Mixer_StreamAddChannel(mixerStream, stream, flags)); }
// メソッド 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); } }