public UserSampleStream(uint freq, uint channels, StreamProc proc, StreamFlag flag, int getData_retryMax = 0) : base(getData_retryMax) { this.streamProc = (handle, buffer, length, user) => this.disposed ? 0x80000000 : this.proc(buffer, length); this.proc = proc; this.handle = _BASS_StreamCreate(freq, channels, (uint)flag, this.streamProc, (IntPtr)this.GetHashCode()); if (this.handle == IntPtr.Zero) { throw new BASSException("UserSampleStream: BASS_StreamCreate Failed."); } }
/// <summary> /// Promotes the current channel to a stream. /// This is necessary if the pitch is shifted, because BASS_FX only works on streams. /// </summary> /// <param name="volume">The stream's initial volume.</param> /// <param name="pitch">The stream's initial pitch.</param> /// <param name="pan">The stream's initial pan.</param> /// <param name="loop">A value indicating whether to loop the stream.</param> private Boolean PromoteToStream(Single volume, Single pitch, Single pan, Boolean loop) { if (BASSUtil.IsValidHandle(stream)) return false; // If the channel is currently playing, pause it. var playing = (State == PlaybackState.Playing); if (playing) { if (!BASSNative.ChannelPause(channel)) throw new BASSException(); } // Get the current position of the playing channel so that we can advance the stream to match. var streampos = (uint)BASSNative.ChannelGetPosition(channel, 0); if (!BASSUtil.IsValidValue(streampos)) throw new BASSException(); // Create a process for streaming data from our sample into the new stream. sampleDataPosition = (int)streampos; sampleDataLength = (int)sampleInfo.length; sampleDataStreamProc = new StreamProc((handle, buffer, length, user) => { if (sampleDataPosition >= sampleDataLength) sampleDataPosition = 0; var byteCount = Math.Min(length, (uint)sampleDataLength - streampos); unsafe { byte* pBufferSrc = (byte*)(sampleData + sampleDataPosition).ToPointer(); byte* pBufferDst = (byte*)(buffer).ToPointer(); for (int i = 0; i < byteCount; i++) { *pBufferDst++ = *pBufferSrc++; } } sampleDataPosition += (int)byteCount; return streampos >= sampleDataLength ? byteCount | BASSNative.BASS_STREAMPROC_END : byteCount; }); // Create a decoding stream based on our sample channel. stream = BASSNative.StreamCreate(sampleInfo.freq, sampleInfo.chans, sampleInfo.flags | BASSNative.BASS_STREAM_DECODE, sampleDataStreamProc, IntPtr.Zero); if (!BASSUtil.IsValidHandle(stream)) throw new BASSException(); // Create an FX stream to shift the sound effect's pitch. stream = BASSFXNative.TempoCreate(stream, BASSNative.BASS_FX_FREESOURCE); if (!BASSUtil.IsValidHandle(stream)) throw new BASSException(); // Set the new stream's attributes. BASSUtil.SetVolume(stream, volume); BASSUtil.SetPitch(stream, pitch); BASSUtil.SetPan(stream, pan); BASSUtil.SetIsLooping(stream, loop); // Stop the old channel and switch to the stream. if (!BASSNative.ChannelStop(channel)) throw new BASSException(); channel = stream; // If we were previously playing, play the stream. if (playing) { if (!BASSNative.ChannelPlay(channel, false)) throw new BASSException(); } promoted = true; return true; }
/// <summary> /// Promotes the current channel to a stream. /// This is necessary if the pitch is shifted, because BASS_FX only works on streams. /// </summary> /// <param name="volume">The stream's initial volume.</param> /// <param name="pitch">The stream's initial pitch.</param> /// <param name="pan">The stream's initial pan.</param> /// <param name="loop">A value indicating whether to loop the stream.</param> private Boolean PromoteToStream(Single volume, Single pitch, Single pan, Boolean loop) { if (BASSUtil.IsValidHandle(stream)) { return(false); } // If the channel is currently playing, pause it. var playing = (State == PlaybackState.Playing); if (playing) { if (!BASSNative.ChannelPause(channel)) { throw new BASSException(); } } // Get the current position of the playing channel so that we can advance the stream to match. var streampos = (uint)BASSNative.ChannelGetPosition(channel, 0); if (!BASSUtil.IsValidValue(streampos)) { throw new BASSException(); } // Create a process for streaming data from our sample into the new stream. sampleDataPosition = (int)streampos; sampleDataLength = (int)sampleInfo.length; sampleDataStreamProc = new StreamProc((handle, buffer, length, user) => { if (sampleDataPosition >= sampleDataLength) { sampleDataPosition = 0; } var byteCount = Math.Min(length, (uint)sampleDataLength - streampos); unsafe { byte *pBufferSrc = (byte *)(sampleData + sampleDataPosition).ToPointer(); byte *pBufferDst = (byte *)(buffer).ToPointer(); for (int i = 0; i < byteCount; i++) { *pBufferDst++ = *pBufferSrc++; } } sampleDataPosition += (int)byteCount; return(streampos >= sampleDataLength ? byteCount | BASSNative.BASS_STREAMPROC_END : byteCount); }); // Create a decoding stream based on our sample channel. stream = BASSNative.StreamCreate(sampleInfo.freq, sampleInfo.chans, sampleInfo.flags | BASSNative.BASS_STREAM_DECODE, sampleDataStreamProc, IntPtr.Zero); if (!BASSUtil.IsValidHandle(stream)) { throw new BASSException(); } // Create an FX stream to shift the sound effect's pitch. stream = BASSFXNative.TempoCreate(stream, BASSNative.BASS_FX_FREESOURCE); if (!BASSUtil.IsValidHandle(stream)) { throw new BASSException(); } // Set the new stream's attributes. BASSUtil.SetVolume(stream, volume); BASSUtil.SetPitch(stream, pitch); BASSUtil.SetPan(stream, pan); BASSUtil.SetIsLooping(stream, loop); // Stop the old channel and switch to the stream. if (!BASSNative.ChannelStop(channel)) { throw new BASSException(); } channel = stream; // If we were previously playing, play the stream. if (playing) { if (!BASSNative.ChannelPlay(channel, false)) { throw new BASSException(); } } promoted = true; return(true); }
public static extern UInt32 StreamCreate(UInt32 freq, UInt32 chans, UInt32 flags, StreamProc proc, IntPtr user);
public static UInt32 BASS_StreamCreate(UInt32 freq, UInt32 chans, UInt32 flags, StreamProc proc, IntPtr user) => BASS_StreamCreate(freq, chans, flags, Marshal.GetFunctionPointerForDelegate(proc), user);