Пример #1
0
        /// <summary>
        /// Releases any BASS resources being held by the player.
        /// </summary>
        private void Release()
        {
            if (stream != 0)
            {
                if (!BASSNative.StreamFree(stream))
                {
                    throw new BASSException();
                }

                stream = 0;
            }

            if (sample != 0)
            {
                if (!BASSNative.SampleFree(sample))
                {
                    throw new BASSException();
                }

                sample = 0;
            }

            channel  = 0;
            promoted = false;
            playing  = null;
        }
Пример #2
0
            /// <summary>
            /// Creates a BASS stream that represents the song.
            /// </summary>
            /// <param name="flags">The flags to apply to the stream that is created.</param>
            /// <returns>The handle to the BASS stream that was created.</returns>
            public UInt32 CreateInstance(UInt32 flags)
            {
                var fileSystemService = FileSystemService.Create();

                var instance   = fileSystemService.OpenRead(file);
                var instanceID = this.nextInstanceID++;

                instances.Add(instanceID, instance);

                var stream = 0u;

                try
                {
                    var procs = new BASS_FILEPROCS(fnClose, fnLength, fnRead, fnSeek);

                    unsafe
                    {
                        stream = BASSNative.StreamCreateFileUser(1, BASSNative.BASS_STREAM_DECODE, &procs, new IntPtr((int)instanceID));
                        if (!BASSUtil.IsValidHandle(stream))
                        {
                            throw new BASSException();
                        }
                    }
                }
                catch
                {
                    instance.Dispose();
                    instances.Remove(instanceID);
                    throw;
                }

                return(stream);
            }
Пример #3
0
        /// <summary>
        /// Initializes a new instance of the BASSSoundEffect class.
        /// </summary>
        /// <param name="uv">The Ultraviolet context.</param>
        /// <param name="filename">The filename of the sample to load.</param>
        public BASSSoundEffect(UltravioletContext uv, String filename)
            : base(uv)
        {
            var fileSystemService = FileSystemService.Create();
            var fileData          = default(Byte[]);

            using (var stream = fileSystemService.OpenRead(filename))
            {
                fileData = new Byte[stream.Length];
                stream.Read(fileData, 0, fileData.Length);
            }

            sample = BASSNative.SampleLoad(fileData, 0, (UInt32)fileData.Length, UInt16.MaxValue, 0);
            if (!BASSUtil.IsValidHandle(sample))
            {
                throw new BASSException();
            }

            if (!BASSNative.SampleGetInfo(sample, out this.sampleInfo))
            {
                throw new BASSException();
            }

            this.data = Marshal.AllocHGlobal((int)sampleInfo.length);
            if (!BASSNative.SampleGetData(sample, this.data))
            {
                throw new BASSException();
            }
        }
Пример #4
0
 /// <summary>
 /// Slides the pan of the specified channel.
 /// </summary>
 /// <param name="handle">The handle that represents the channel to slide.</param>
 /// <param name="pan">The channel's new pan.</param>
 /// <param name="time">The time over which to perform the slide.</param>
 public static void SlidePan(UInt32 handle, Single pan, TimeSpan time)
 {
     if (!BASSNative.ChannelSlideAttribute(handle, BASSAttrib.ATTRIB_PAN, pan, (uint)time.TotalMilliseconds))
     {
         throw new BASSException();
     }
 }
Пример #5
0
        /// <summary>
        /// Sets the pitch of the specified channel.
        /// </summary>
        /// <param name="handle">The handle that represents the channel to adjust.</param>
        /// <param name="pitch">The channel's new pitch.</param>
        public static void SetPitch(UInt32 handle, Single pitch)
        {
            if (BASSNative.ChannelIsSliding(handle, BASSAttrib.ATTRIB_TEMPO_PITCH))
            {
                if (!BASSNative.ChannelSlideAttribute(handle, BASSAttrib.ATTRIB_TEMPO_PITCH, pitch * SemitonesPerOctave, 0))
                {
                    throw new BASSException();
                }
            }
            else
            {
                if (!BASSNative.ChannelSetAttribute(handle, BASSAttrib.ATTRIB_TEMPO_PITCH, pitch * SemitonesPerOctave))
                {
                    throw new BASSException();
                }
            }

            var tempo = (Math.Pow(2.0, pitch) - 1.0) * 100.0;

            if (BASSNative.ChannelIsSliding(handle, BASSAttrib.ATTRIB_TEMPO))
            {
                if (!BASSNative.ChannelSlideAttribute(handle, BASSAttrib.ATTRIB_TEMPO, (float)tempo, 0))
                {
                    throw new BASSException();
                }
            }
            else
            {
                if (!BASSNative.ChannelSetAttribute(handle, BASSAttrib.ATTRIB_TEMPO, (float)tempo))
                {
                    throw new BASSException();
                }
            }
        }
Пример #6
0
 /// <summary>
 /// Performs custom looping when a loop range is specified.
 /// </summary>
 private void SyncLoop(UInt32 handle, UInt32 channel, UInt32 data, IntPtr user)
 {
     if (!BASSNative.ChannelSetPosition(channel, (UInt32)user, 0))
     {
         throw new BASSException();
     }
 }
Пример #7
0
        /// <summary>
        /// Updates the global volume of streams to match the subsystem's current settings.
        /// </summary>
        private void UpdateStreamVolume()
        {
            var volumeStream = (audioMuted || songsMuted) ? 0 : (uint)(10000 * audioMasterVolume * songsMasterVolume);

            if (!BASSNative.SetConfig(BASSConfig.CONFIG_GVOL_STREAM, volumeStream))
            {
                throw new BASSException();
            }
        }
Пример #8
0
        /// <summary>
        /// Updates the global volume of samples to match the subsystem's current settings.
        /// </summary>
        private void UpdateSampleVolume()
        {
            var volumeSample = (audioMuted || soundEffectsMuted) ? 0 : (uint)(10000 * audioMasterVolume * soundEffectsMasterVolume);

            if (!BASSNative.SetConfig(BASSConfig.CONFIG_GVOL_SAMPLE, volumeSample))
            {
                throw new BASSException();
            }
        }
Пример #9
0
        /// <summary>
        /// Plays the specified song.
        /// </summary>
        private Boolean PlayInternal(Song song, Single volume, Single pitch, Single pan, TimeSpan?loopStart, TimeSpan?loopLength)
        {
            Ultraviolet.ValidateResource(song);

            Stop();

            stream = ((BASSSong)song).CreateStream(BASSNative.BASS_STREAM_DECODE);
            stream = BASSFXNative.TempoCreate(stream, BASSNative.BASS_FX_FREESOURCE | BASSNative.BASS_STREAM_AUTOFREE);
            if (!BASSUtil.IsValidHandle(stream))
            {
                throw new BASSException();
            }

            var autoloop = loopStart.HasValue && !loopLength.HasValue;
            var syncloop = loopStart.HasValue && !autoloop;

            BASSUtil.SetIsLooping(stream, autoloop);
            BASSUtil.SetVolume(stream, MathUtil.Clamp(volume, 0f, 1f));
            BASSUtil.SetPitch(stream, MathUtil.Clamp(pitch, -1f, 1f));
            BASSUtil.SetPan(stream, MathUtil.Clamp(pan, -1f, 1f));

            if (loopStart > TimeSpan.Zero && loopLength <= TimeSpan.Zero)
            {
                throw new ArgumentException(nameof(loopLength));
            }

            if (syncloop)
            {
                var loopStartInBytes = BASSNative.ChannelSeconds2Bytes(stream, loopStart.Value.TotalSeconds);
                var loopEndInBytes   = BASSNative.ChannelSeconds2Bytes(stream, (loopStart + loopLength).Value.TotalSeconds);
                syncLoopDelegate = SyncLoop;
                syncLoop         = BASSNative.ChannelSetSync(stream, BASSSync.SYNC_POS, loopEndInBytes, syncLoopDelegate, new IntPtr((Int32)loopStartInBytes));
                if (syncLoop == 0)
                {
                    throw new BASSException();
                }
            }

            syncEndDelegate = SyncEnd;
            syncEnd         = BASSNative.ChannelSetSync(stream, BASSSync.SYNC_END, 0, syncEndDelegate, IntPtr.Zero);
            if (syncEnd == 0)
            {
                throw new BASSException();
            }

            if (!BASSNative.ChannelPlay(stream, true))
            {
                throw new BASSException();
            }

            OnStateChanged();
            OnSongStarted();

            return(true);
        }
Пример #10
0
        /// <summary>
        /// Suspends all audio output.
        /// </summary>
        public void Suspend()
        {
            Contract.EnsureNotDisposed(this, Disposed);

            if (!BASSNative.Pause())
            {
                throw new BASSException();
            }

            suspended = true;
        }
Пример #11
0
        /// <summary>
        /// Resumes audio output after a call to <see cref="Suspend"/>.
        /// </summary>
        public void Resume()
        {
            Contract.EnsureNotDisposed(this, Disposed);

            if (!BASSNative.Start())
            {
                throw new BASSException();
            }

            suspended = false;
        }
Пример #12
0
        /// <summary>
        /// Sets a value indicating whether the specified channel is looping.
        /// </summary>
        /// <param name="handle">The handle of the channel to modify.</param>
        /// <param name="looping">A value indicating whether the channel is looping.</param>
        public static void SetIsLooping(UInt32 handle, Boolean looping)
        {
            var flags = looping ?
                        BASSNative.ChannelFlags(handle, BASSNative.BASS_SAMPLE_LOOP, BASSNative.BASS_SAMPLE_LOOP) :
                        BASSNative.ChannelFlags(handle, 0, BASSNative.BASS_SAMPLE_LOOP);

            if (!BASSUtil.IsValidValue(flags))
            {
                throw new BASSException();
            }
        }
Пример #13
0
        /// <summary>
        /// Gets a value indicating whether the specified channel is looping.
        /// </summary>
        /// <param name="handle">The handle of the channel to evaluate.</param>
        /// <returns>true if the channel is looping; otherwise, false.</returns>
        public static Boolean GetIsLooping(UInt32 handle)
        {
            var flags = BASSNative.ChannelFlags(handle, 0, 0);

            if (!BASSUtil.IsValidValue(flags))
            {
                throw new BASSException();
            }

            return((flags & BASSNative.BASS_SAMPLE_LOOP) == BASSNative.BASS_SAMPLE_LOOP);
        }
Пример #14
0
 /// <summary>
 /// Gets the pan of the specified channel.
 /// </summary>
 /// <param name="handle">The handle that represents the channel to evaluate.</param>
 /// <returns>The channel's pan.</returns>
 public static Single GetPan(UInt32 handle)
 {
     unsafe
     {
         Single value;
         if (!BASSNative.ChannelGetAttribute(handle, BASSAttrib.ATTRIB_PAN, &value))
         {
             throw new BASSException();
         }
         return(value);
     }
 }
Пример #15
0
 /// <summary>
 /// Gets the pitch of the specified channel.
 /// </summary>
 /// <param name="handle">The handle that represents the channel to evaluate.</param>
 /// <returns>The channel's pitch.</returns>
 public static Single GetPitch(UInt32 handle)
 {
     unsafe
     {
         Single value;
         if (!BASSNative.ChannelGetAttribute(handle, BASSAttrib.ATTRIB_TEMPO_PITCH, &value))
         {
             throw new BASSException();
         }
         return(value / SemitonesPerOctave);
     }
 }
Пример #16
0
        /// <summary>
        /// Reads any supported tags which are contained by the specified stream.
        /// </summary>
        private void ReadTagsFromStream(UInt32 stream)
        {
            var tagsOgg = default(IDictionary <String, String>);

            if (BASSNative.ChannelGetTags_Ogg(stream, out tagsOgg))
            {
                foreach (var tagOgg in tagsOgg)
                {
                    tags.Add(tagOgg.Key, tagOgg.Value);
                }
            }
        }
Пример #17
0
        /// <inheritdoc/>
        public override void Resume()
        {
            Contract.EnsureNotDisposed(this, Disposed);

            if (State == PlaybackState.Paused)
            {
                if (!BASSNative.ChannelPlay(stream, false))
                {
                    throw new BASSException();
                }

                OnStateChanged();
            }
        }
Пример #18
0
        /// <inheritdoc/>
        public override void Stop()
        {
            Contract.EnsureNotDisposed(this, Disposed);

            if (State != PlaybackState.Stopped)
            {
                if (!BASSNative.ChannelStop(channel))
                {
                    throw new BASSException();
                }
            }

            Release();
        }
Пример #19
0
        /// <inheritdoc/>
        public override void Pause()
        {
            Contract.EnsureNotDisposed(this, Disposed);

            EnsureChannelIsValid();

            if (State == PlaybackState.Playing)
            {
                if (!BASSNative.ChannelPause(channel))
                {
                    throw new BASSException();
                }
            }
        }
Пример #20
0
        /// <summary>
        /// Slides the pitch of the specified channel.
        /// </summary>
        /// <param name="handle">The handle that represents the channel to slide.</param>
        /// <param name="pitch">The channel's new pitch.</param>
        /// <param name="time">The time over which to perform the slide.</param>
        public static void SlidePitch(UInt32 handle, Single pitch, TimeSpan time)
        {
            if (!BASSNative.ChannelSlideAttribute(handle, BASSAttrib.ATTRIB_TEMPO_PITCH, pitch * SemitonesPerOctave, (uint)time.TotalMilliseconds))
            {
                throw new BASSException();
            }

            var tempo = (Math.Pow(2.0, pitch) - 1.0) * 100.0;

            if (!BASSNative.ChannelSlideAttribute(handle, BASSAttrib.ATTRIB_TEMPO, (float)tempo, (uint)time.TotalMilliseconds))
            {
                throw new BASSException();
            }
        }
Пример #21
0
        /// <summary>
        /// Sets the position of the specified channel.
        /// </summary>
        /// <param name="handle">The handle of the channel to modify.</param>
        /// <param name="position">The position in seconds to which to set the channel.</param>
        public static void SetPositionInSeconds(UInt32 handle, Double position)
        {
            var positionInBytes = BASSNative.ChannelSeconds2Bytes(handle, position);

            if (!BASSUtil.IsValidValue(positionInBytes))
            {
                throw new BASSException();
            }

            if (!BASSNative.ChannelSetPosition(handle, positionInBytes, 0))
            {
                throw new BASSException();
            }
        }
Пример #22
0
        /// <summary>
        /// Releases resources associated with the object.
        /// </summary>
        /// <param name="disposing">true if the object is being disposed; false if the object is being finalized.</param>
        protected override void Dispose(Boolean disposing)
        {
            if (!BASSNative.Free())
            {
                throw new BASSException();
            }

            if (disposing && !Ultraviolet.Disposed)
            {
                Ultraviolet.Messages.Unsubscribe(this);
            }

            base.Dispose(disposing);
        }
Пример #23
0
        public BASSUltravioletAudio(UltravioletContext uv)
            : base(uv)
        {
            var device = -1;
            var freq   = 44100u;

            if (!BASSNative.Init(device, freq, 0, IntPtr.Zero, IntPtr.Zero))
            {
                throw new BASSException();
            }

            uv.Messages.Subscribe(this, UltravioletMessages.ApplicationSuspending);
            uv.Messages.Subscribe(this, UltravioletMessages.ApplicationResumed);
        }
Пример #24
0
        /// <inheritdoc/>
        public override void Play()
        {
            Contract.EnsureNotDisposed(this, Disposed);

            var channel = BASSNative.SampleGetChannel(sample, false);

            if (!BASSUtil.IsValidHandle(channel))
            {
                throw new BASSException();
            }

            if (!BASSNative.ChannelPlay(channel, true))
            {
                throw new BASSException();
            }
        }
Пример #25
0
        /// <summary>
        /// Plays a sound effect.
        /// </summary>
        private Boolean PlayInternal(SoundEffect soundEffect, Single volume, Single pitch, Single pan, Boolean loop = false)
        {
            Contract.EnsureNotDisposed(this, Disposed);

            // Stop any sound that's already playing.
            Stop();

            // Retrieve the sample data from the sound effect.
            Ultraviolet.ValidateResource(soundEffect);
            var bassfx = (BASSSoundEffect)soundEffect;
            var sample = bassfx.GetSampleData(out this.sampleData, out this.sampleInfo);

            // Get a channel on which to play the sample.
            channel = BASSNative.SampleGetChannel(sample, true);
            if (!BASSUtil.IsValidHandle(channel))
            {
                var error = BASSNative.ErrorGetCode();
                if (error == BASSNative.BASS_ERROR_NOCHAN)
                {
                    return(false);
                }

                throw new BASSException(error);
            }

            // Set the channel's attributes.
            if (pitch == 0)
            {
                BASSUtil.SetIsLooping(channel, loop);
                BASSUtil.SetVolume(channel, MathUtil.Clamp(volume, 0f, 1f));
                BASSUtil.SetPan(channel, MathUtil.Clamp(pan, -1f, 1f));
            }
            else
            {
                PromoteToStream(volume, MathUtil.Clamp(pitch, -1f, 1f), pan, loop);
            }

            // Play the channel.
            if (!BASSNative.ChannelPlay(channel, true))
            {
                throw new BASSException();
            }

            this.playing = soundEffect;

            return(true);
        }
Пример #26
0
        /// <inheritdoc/>
        public override void Play(Single volume, Single pitch, Single pan)
        {
            Contract.EnsureNotDisposed(this, Disposed);

            var channel = 0u;

            if (pitch == 0)
            {
                channel = BASSNative.SampleGetChannel(sample, false);
                if (!BASSUtil.IsValidHandle(channel))
                {
                    throw new BASSException();
                }
            }
            else
            {
                var stream = BASSNative.StreamCreate(sampleInfo.freq, sampleInfo.chans, sampleInfo.flags | BASSNative.BASS_STREAM_DECODE, BASSNative.STREAMPROC_PUSH, IntPtr.Zero);
                if (!BASSUtil.IsValidHandle(stream))
                {
                    throw new BASSException();
                }

                var pushed = BASSNative.StreamPutData(stream, data, sampleInfo.length);
                if (!BASSUtil.IsValidValue(pushed))
                {
                    throw new BASSException();
                }

                stream = BASSFXNative.TempoCreate(stream, BASSNative.BASS_FX_FREESOURCE | BASSNative.BASS_STREAM_AUTOFREE);
                if (!BASSUtil.IsValidHandle(stream))
                {
                    throw new BASSException();
                }

                channel = stream;

                BASSUtil.SetPitch(channel, MathUtil.Clamp(pitch, -1f, 1f));
            }

            BASSUtil.SetVolume(channel, MathUtil.Clamp(volume, 0f, 1f));
            BASSUtil.SetPan(channel, MathUtil.Clamp(pan, -1f, 1f));

            if (!BASSNative.ChannelPlay(channel, false))
            {
                throw new BASSException();
            }
        }
Пример #27
0
 /// <summary>
 /// Sets the volume of the specified channel.
 /// </summary>
 /// <param name="handle">The handle that represents the channel to adjust.</param>
 /// <param name="volume">The channel's new volume./</param>
 public static void SetVolume(UInt32 handle, Single volume)
 {
     if (BASSNative.ChannelIsSliding(handle, BASSAttrib.ATTRIB_VOL))
     {
         if (!BASSNative.ChannelSlideAttribute(handle, BASSAttrib.ATTRIB_VOL, volume, 0))
         {
             throw new BASSException();
         }
     }
     else
     {
         if (!BASSNative.ChannelSetAttribute(handle, BASSAttrib.ATTRIB_VOL, volume))
         {
             throw new BASSException();
         }
     }
 }
Пример #28
0
 /// <summary>
 /// Sets the pan of the specified channel.
 /// </summary>
 /// <param name="handle">The handle that represents the channel to adjust.</param>
 /// <param name="pan">The channel's new pan.</param>
 public static void SetPan(UInt32 handle, Single pan)
 {
     if (BASSNative.ChannelIsSliding(handle, BASSAttrib.ATTRIB_PAN))
     {
         if (!BASSNative.ChannelSlideAttribute(handle, BASSAttrib.ATTRIB_PAN, pan, 0))
         {
             throw new BASSException();
         }
     }
     else
     {
         if (!BASSNative.ChannelSetAttribute(handle, BASSAttrib.ATTRIB_PAN, pan))
         {
             throw new BASSException();
         }
     }
 }
Пример #29
0
        /// <summary>
        /// Gets the duration of the specified channel in seconds.
        /// </summary>
        /// <param name="handle">The handle of the channel to evaluate.</param>
        /// <returns>The duration of the specified channel in seconds.</returns>
        public static Double GetDurationInSeconds(UInt32 handle)
        {
            var length = BASSNative.ChannelGetLength(handle, 0);

            if (!BASSUtil.IsValidValue(length))
            {
                throw new BASSException();
            }

            var seconds = BASSNative.ChannelBytes2Seconds(handle, length);

            if (seconds < 0)
            {
                throw new BASSException();
            }

            return(seconds);
        }
Пример #30
0
        /// <summary>
        /// Gets the position of the specified channel.
        /// </summary>
        /// <param name="handle">The handle of the channel to evaluate.</param>
        /// <returns>The current position of the channel in seconds.</returns>
        public static Double GetPositionInSeconds(UInt32 handle)
        {
            var position = BASSNative.ChannelGetPosition(handle, 0);

            if (!BASSUtil.IsValidValue(position))
            {
                throw new BASSException();
            }

            var seconds = BASSNative.ChannelBytes2Seconds(handle, position);

            if (seconds < 0)
            {
                throw new BASSException();
            }

            return(seconds);
        }