/// <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); }