Port only distinct new feature work

This commit is contained in:
Matt Nadareski
2021-08-24 22:11:25 -07:00
parent 24d1114795
commit a799d5ede9
11 changed files with 371 additions and 11 deletions

View File

@@ -12,8 +12,10 @@
| --- | ------ |
| **F1** | Open Settings Window |
| **F2** | Load New Image |
| **S** | Save Track(s) |
| **Space** | Toggle Play / Pause |
| **Esc** | Stop Playback |
| **~** | Eject |
| **→** | Next Track |
| **←** | Previous Track |
| **]** | Next Index |
@@ -25,6 +27,10 @@
| **M** | Mute |
| **E** | Toggle Emphasis |
For Save Track(s):
- Holding no modifying keys will prompt to save the current track
- Holding **Shift** will prompt to save all tracks (including hidden)
For both Volume Up and Volume Down:
- Holding **Ctrl** will move in increments of 2
- Holding **Shift** will move in increments of 5

View File

@@ -40,6 +40,23 @@ namespace RedBookPlayer.GUI.ViewModels
PlayerView?.ViewModel?.ExecuteLoad();
}
// Save track(s)
else if(e.Key == App.Settings.SaveTrackKey)
{
if(PlayerView?.ViewModel == null || !PlayerView.ViewModel.Initialized)
return;
var dialog = new OpenFolderDialog();
string path = await dialog.ShowAsync(App.MainWindow);
if(string.IsNullOrWhiteSpace(path))
return;
if(e.KeyModifiers.HasFlag(KeyModifiers.Shift))
PlayerView.ViewModel.ExtractAllTracksToWav(path);
else
PlayerView.ViewModel.ExtractSingleTrackToWav((uint)PlayerView.ViewModel.CurrentTrackNumber, path);
}
// Toggle playback
else if(e.Key == App.Settings.TogglePlaybackKey || e.Key == Key.MediaPlayPause)
{
@@ -52,6 +69,12 @@ namespace RedBookPlayer.GUI.ViewModels
PlayerView?.ViewModel?.ExecuteStop();
}
// Eject
else if(e.Key == App.Settings.EjectKey)
{
PlayerView?.ViewModel?.ExecuteEject();
}
// Next Track
else if(e.Key == App.Settings.NextTrackKey || e.Key == Key.MediaNextTrack)
{

View File

@@ -6,11 +6,9 @@ using System.Linq;
using System.Reactive;
using System.Threading.Tasks;
using System.Xml;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Threading;
using ReactiveUI;
using RedBookPlayer.Models;
@@ -193,6 +191,15 @@ namespace RedBookPlayer.GUI.ViewModels
private set => this.RaiseAndSetIfChanged(ref _dataPlayback, value);
}
/// <summary>
/// Indicates the repeat mode
/// </summary>
public RepeatMode RepeatMode
{
get => _repeatMode;
private set => this.RaiseAndSetIfChanged(ref _repeatMode, value);
}
/// <summary>
/// Indicates if de-emphasis should be applied
/// </summary>
@@ -214,6 +221,7 @@ namespace RedBookPlayer.GUI.ViewModels
private bool _initialized;
private PlayerState _playerState;
private DataPlayback _dataPlayback;
private RepeatMode _repeatMode;
private bool _applyDeEmphasis;
private int _volume;
@@ -250,6 +258,11 @@ namespace RedBookPlayer.GUI.ViewModels
/// </summary>
public ReactiveCommand<Unit, Unit> StopCommand { get; }
/// <summary>
/// Command for ejecting the current disc
/// </summary>
public ReactiveCommand<Unit, Unit> EjectCommand { get; }
/// <summary>
/// Command for moving to the next track
/// </summary>
@@ -334,6 +347,7 @@ namespace RedBookPlayer.GUI.ViewModels
PauseCommand = ReactiveCommand.Create(ExecutePause);
TogglePlayPauseCommand = ReactiveCommand.Create(ExecuteTogglePlayPause);
StopCommand = ReactiveCommand.Create(ExecuteStop);
EjectCommand = ReactiveCommand.Create(ExecuteEject);
NextTrackCommand = ReactiveCommand.Create(ExecuteNextTrack);
PreviousTrackCommand = ReactiveCommand.Create(ExecutePreviousTrack);
NextIndexCommand = ReactiveCommand.Create(ExecuteNextIndex);
@@ -359,15 +373,16 @@ namespace RedBookPlayer.GUI.ViewModels
/// </summary>
/// <param name="path">Path to the disc image</param>
/// <param name="options">Options to pass to the optical disc factory</param>
/// <param name="repeatMode">RepeatMode for sound output</param>
/// <param name="autoPlay">True if playback should begin immediately, false otherwise</param>
public void Init(string path, OpticalDiscOptions options, bool autoPlay)
public void Init(string path, OpticalDiscOptions options, RepeatMode repeatMode, bool autoPlay)
{
// Stop current playback, if necessary
if(PlayerState != PlayerState.NoDisc)
ExecuteStop();
// Attempt to initialize Player
_player.Init(path, options, autoPlay);
_player.Init(path, options, repeatMode, autoPlay);
if(_player.Initialized)
{
_player.PropertyChanged += PlayerStateChanged;
@@ -397,6 +412,11 @@ namespace RedBookPlayer.GUI.ViewModels
/// </summary>
public void ExecuteStop() => _player?.Stop();
/// <summary>
/// Eject the currently loaded disc
/// </summary>
public void ExecuteEject() => _player?.Eject();
/// <summary>
/// Move to the next playable track
/// </summary>
@@ -578,13 +598,14 @@ namespace RedBookPlayer.GUI.ViewModels
DataPlayback = App.Settings.DataPlayback,
GenerateMissingToc = App.Settings.GenerateMissingTOC,
LoadHiddenTracks = App.Settings.PlayHiddenTracks,
SessionHandling = App.Settings.SessionHandling,
};
// Ensure the context and view model are set
App.PlayerView.DataContext = this;
App.PlayerView.ViewModel = this;
Init(path, options, App.Settings.AutoPlay);
Init(path, options, App.Settings.RepeatMode, App.Settings.AutoPlay);
if(Initialized)
App.MainWindow.Title = "RedBookPlayer - " + path.Split('/').Last().Split('\\').Last();
@@ -599,8 +620,23 @@ namespace RedBookPlayer.GUI.ViewModels
{
SetDataPlayback(App.Settings.DataPlayback);
SetLoadHiddenTracks(App.Settings.PlayHiddenTracks);
SetRepeatMode(App.Settings.RepeatMode);
SetSessionHandling(App.Settings.SessionHandling);
}
/// <summary>
/// Extract a single track from the image to WAV
/// </summary>
/// <param name="trackNumber"></param>
/// <param name="outputDirectory">Output path to write data to</param
public void ExtractSingleTrackToWav(uint trackNumber, string outputDirectory) => _player?.ExtractSingleTrackToWav(trackNumber, outputDirectory);
/// <summary>
/// Extract all tracks from the image to WAV
/// </summary>
/// <param name="outputDirectory">Output path to write data to</param
public void ExtractAllTracksToWav(string outputDirectory) => _player?.ExtractAllTracksToWav(outputDirectory);
/// <summary>
/// Set data playback method [CompactDisc only]
/// </summary>
@@ -613,6 +649,18 @@ namespace RedBookPlayer.GUI.ViewModels
/// <param name="load">True to enable loading hidden tracks, false otherwise</param>
public void SetLoadHiddenTracks(bool load) => _player?.SetLoadHiddenTracks(load);
/// <summary>
/// Set repeat mode
/// </summary>
/// <param name="repeatMode">New repeat mode value</param>
public void SetRepeatMode(RepeatMode repeatMode) => _player?.SetRepeatMode(repeatMode);
/// <summary>
/// Set session handling
/// </summary>
/// <param name="sessionHandling">New session handling value</param>
public void SetSessionHandling(SessionHandling sessionHandling) => _player?.SetSessionHandling(sessionHandling);
/// <summary>
/// Generate the digit string to be interpreted by the frontend
/// </summary>
@@ -754,6 +802,7 @@ namespace RedBookPlayer.GUI.ViewModels
CurrentTrackNumber = _player.CurrentTrackNumber;
CurrentTrackIndex = _player.CurrentTrackIndex;
CurrentTrackSession = _player.CurrentTrackSession;
CurrentSector = _player.CurrentSector;
SectionStartSector = _player.SectionStartSector;
@@ -766,6 +815,7 @@ namespace RedBookPlayer.GUI.ViewModels
PlayerState = _player.PlayerState;
DataPlayback = _player.DataPlayback;
RepeatMode = _player.RepeatMode;
ApplyDeEmphasis = _player.ApplyDeEmphasis;
Volume = _player.Volume;

View File

@@ -21,6 +21,18 @@ namespace RedBookPlayer.GUI.ViewModels
[JsonIgnore]
public List<DataPlayback> DataPlaybackValues => GenerateDataPlaybackList();
/// <summary>
/// List of all repeat mode values
/// </summary>
[JsonIgnore]
public List<RepeatMode> RepeatModeValues => GenerateRepeatModeList();
/// <summary>
/// List of all session handling values
/// </summary>
[JsonIgnore]
public List<SessionHandling> SessionHandlingValues => GenerateSessionHandlingList();
/// <summary>
/// List of all themes
/// </summary>
@@ -57,6 +69,16 @@ namespace RedBookPlayer.GUI.ViewModels
/// </summary>
public DataPlayback DataPlayback { get; set; } = DataPlayback.Skip;
/// <summary>
/// Indicates how to repeat tracks
/// </summary>
public RepeatMode RepeatMode { get; set; } = RepeatMode.All;
/// <summary>
/// Indicates how to handle tracks on different sessions
/// </summary>
public SessionHandling SessionHandling { get; set; } = SessionHandling.FirstSessionOnly;
/// <summary>
/// Indicates the default playback volume
/// </summary>
@@ -102,6 +124,11 @@ namespace RedBookPlayer.GUI.ViewModels
/// </summary>
public Key LoadImageKey { get; set; } = Key.F2;
/// <summary>
/// Key assigned to save the current track or all tracks
/// </summary>
public Key SaveTrackKey { get; set; } = Key.S;
/// <summary>
/// Key assigned to toggle play and pause
/// </summary>
@@ -253,6 +280,16 @@ namespace RedBookPlayer.GUI.ViewModels
/// </summary>
private List<Key> GenerateKeyList() => Enum.GetValues(typeof(Key)).Cast<Key>().ToList();
/// <summary>
/// Generate the list of RepeatMode values
/// </summary>
private List<RepeatMode> GenerateRepeatModeList() => Enum.GetValues(typeof(RepeatMode)).Cast<RepeatMode>().ToList();
/// <summary>
/// Generate the list of SessionHandling values
/// </summary>
private List<SessionHandling> GenerateSessionHandlingList() => Enum.GetValues(typeof(SessionHandling)).Cast<SessionHandling>().ToList();
/// <summary>
/// Generate the list of valid themes
/// </summary>

View File

@@ -30,6 +30,16 @@
<ComboBox Grid.Row="0" Grid.Column="1" Name="DataPlayback" Margin="8,0,0,0" Width="120"
Items="{Binding DataPlaybackValues}" SelectedItem="{Binding DataPlayback, Mode=TwoWay}" />
</WrapPanel>
<WrapPanel Margin="0,0,0,16">
<TextBlock Grid.Row="0" Grid.Column="0" Width="120">Session Handling</TextBlock>
<ComboBox Grid.Row="0" Grid.Column="1" Name="SessionHandling" Margin="8,0,0,0" Width="120"
Items="{Binding SessionHandlingValues}" SelectedItem="{Binding SessionHandling, Mode=TwoWay}" />
</WrapPanel>
<WrapPanel Margin="0,0,0,16">
<TextBlock Grid.Row="0" Grid.Column="0" Width="120">Repeat Mode</TextBlock>
<ComboBox Grid.Row="0" Grid.Column="1" Name="RepeatMode" Margin="8,0,0,0" Width="120"
Items="{Binding RepeatModeValues}" SelectedItem="{Binding RepeatMode, Mode=TwoWay}" />
</WrapPanel>
<WrapPanel Margin="0,0,0,16">
<CheckBox IsChecked="{Binding GenerateMissingTOC}" Margin="0,0,8,0"/>
<TextBlock VerticalAlignment="Center">Generate a TOC if the disc is missing one</TextBlock>
@@ -78,6 +88,12 @@
Items="{Binding KeyboardList}" SelectedItem="{Binding LoadImageKey, Mode=TwoWay}"
HorizontalAlignment="Right" Margin="8,0,0,0" Width="120"/>
<!-- Save Track -->
<TextBlock Grid.Row="1" Grid.Column="0" Width="120">Save Track(s)</TextBlock>
<ComboBox Grid.Row="1" Grid.Column="1" Name="SaveTrackKeyBind"
Items="{Binding KeyboardList}" SelectedItem="{Binding SaveTrackKey, Mode=TwoWay}"
HorizontalAlignment="Right" Margin="8,0,0,0" Width="120"/>
<!-- Toggle Play/Pause -->
<TextBlock Grid.Row="2" Grid.Column="0" Width="120">Toggle Play/Pause</TextBlock>
<ComboBox Grid.Row="2" Grid.Column="1" Name="TogglePlaybackKeyBind"

View File

@@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
using Aaru.Decoders.CD;
using Aaru.Helpers;
using CSCore.Codecs.WAV;
using ReactiveUI;
using static Aaru.Decoders.CD.FullTOC;
@@ -69,7 +71,8 @@ namespace RedBookPlayer.Models.Discs
SetTrackFlags(track);
// If the track is playable, just return
if(TrackType == TrackType.Audio || DataPlayback != DataPlayback.Skip)
if((TrackType == TrackType.Audio || DataPlayback != DataPlayback.Skip)
&& (SessionHandling == SessionHandling.AllSessions || track.TrackSession == 1))
{
break;
}
@@ -102,6 +105,7 @@ namespace RedBookPlayer.Models.Discs
TotalIndexes = cachedTrack.Indexes.Keys.Max();
CurrentTrackIndex = cachedTrack.Indexes.Keys.Min();
CurrentTrackSession = cachedTrack.TrackSession;
}
}
@@ -135,6 +139,13 @@ namespace RedBookPlayer.Models.Discs
}
}
/// <inheritdoc/>
public override ushort CurrentTrackSession
{
get => _currentTrackSession;
protected set => this.RaiseAndSetIfChanged(ref _currentTrackSession, value);
}
/// <inheritdoc/>
public override ulong CurrentSector
{
@@ -229,6 +240,11 @@ namespace RedBookPlayer.Models.Discs
/// </summary>
public bool LoadHiddenTracks { get; set; } = false;
/// <summary>
/// Indicates how tracks on different session should be handled
/// </summary>
public SessionHandling SessionHandling { get; set; } = SessionHandling.AllSessions;
private bool _quadChannel;
private bool _isDataTrack;
private bool _copyAllowed;
@@ -248,6 +264,11 @@ namespace RedBookPlayer.Models.Discs
/// </summary>
private ushort _currentTrackIndex = 0;
/// <summary>
/// Current track session
/// </summary>
private ushort _currentTrackSession = 0;
/// <summary>
/// Current sector number
/// </summary>
@@ -274,6 +295,7 @@ namespace RedBookPlayer.Models.Discs
DataPlayback = options.DataPlayback;
_generateMissingToc = options.GenerateMissingToc;
LoadHiddenTracks = options.LoadHiddenTracks;
SessionHandling = options.SessionHandling;
}
/// <inheritdoc/>
@@ -417,6 +439,44 @@ namespace RedBookPlayer.Models.Discs
#region Helpers
/// <inheritdoc/>
public override void ExtractTrackToWav(uint trackNumber, string outputDirectory)
{
if(_image == null)
return;
// Get the track with that value, if possible
Track track = _image.Tracks.FirstOrDefault(t => t.TrackSequence == trackNumber);
// If the track isn't valid, we can't do anything
if(track == null || track.TrackType != TrackType.Audio)
return;
// Read in the track data to a buffer
uint length = (uint)(track.TrackEndSector - track.TrackStartSector);
byte[] buffer = _image.ReadSectors(track.TrackStartSector, length);
// Build the WAV output
string filename = Path.Combine(outputDirectory, $"Track {trackNumber.ToString().PadLeft(2, '0')}.wav");
using(WaveWriter waveWriter = new WaveWriter(filename, new CSCore.WaveFormat()))
{
// Write out to the file
waveWriter.Write(buffer, 0, buffer.Length);
}
}
/// <inheritdoc/>
public override void ExtractAllTracksToWav(string outputDirectory)
{
if(_image == null)
return;
foreach(Track track in _image.Tracks)
{
ExtractTrackToWav(track.TrackSequence, outputDirectory);
}
}
/// <inheritdoc/>
public override void LoadTrack(int trackNumber)
{

View File

@@ -23,6 +23,11 @@ namespace RedBookPlayer.Models.Discs
/// </summary>
public abstract ushort CurrentTrackIndex { get; protected set; }
/// <summary>
/// Current track session
/// </summary>
public abstract ushort CurrentTrackSession { get; protected set; }
/// <summary>
/// Current sector number
/// </summary>
@@ -122,6 +127,19 @@ namespace RedBookPlayer.Models.Discs
#region Helpers
/// <summary>
/// Extract a track to WAV
/// </summary>
/// <param name="trackNumber">Track number to extract</param>
/// <param name="outputDirectory">Output path to write data to</param
public abstract void ExtractTrackToWav(uint trackNumber, string outputDirectory);
/// <summary>
/// Extract all tracks to WAV
/// </summary>
/// <param name="outputDirectory">Output path to write data to</param
public abstract void ExtractAllTracksToWav(string outputDirectory);
/// <summary>
/// Load the desired track, if possible
/// </summary>

View File

@@ -19,6 +19,11 @@ namespace RedBookPlayer.Models.Discs
/// </summary>
public bool LoadHiddenTracks { get; set; } = false;
/// <summary>
/// Indicates how tracks on different session should be handled
/// </summary>
public SessionHandling SessionHandling { get; set; } = SessionHandling.AllSessions;
#endregion
}
}

View File

@@ -46,4 +46,41 @@ namespace RedBookPlayer.Models
/// </summary>
Playing,
}
/// <summary>
/// Playback repeat mode
/// </summary>
public enum RepeatMode
{
/// <summary>
/// No repeat
/// </summary>
None,
/// <summary>
/// Repeat a single track
/// </summary>
Single,
/// <summary>
/// Repeat all tracks
/// </summary>
All,
}
/// <summary>
/// Determine how to handle different sessions
/// </summary>
public enum SessionHandling
{
/// <summary>
/// Allow playing tracks from all sessions
/// </summary>
AllSessions = 0,
/// <summary>
/// Only play tracks from the first session
/// </summary>
FirstSessionOnly = 1,
}
}

View File

@@ -39,6 +39,15 @@ namespace RedBookPlayer.Models.Hardware
private set => this.RaiseAndSetIfChanged(ref _currentTrackIndex, value);
}
/// <summary>
/// Current track session
/// </summary>
public ushort CurrentTrackSession
{
get => _currentTrackSession;
private set => this.RaiseAndSetIfChanged(ref _currentTrackSession, value);
}
/// <summary>
/// Current sector number
/// </summary>
@@ -129,6 +138,7 @@ namespace RedBookPlayer.Models.Hardware
private int _currentTrackNumber;
private ushort _currentTrackIndex;
private ushort _currentTrackSession;
private ulong _currentSector;
private ulong _sectionStartSector;
@@ -160,6 +170,15 @@ namespace RedBookPlayer.Models.Hardware
private set => this.RaiseAndSetIfChanged(ref _dataPlayback, value);
}
/// <summary>
/// Indicates the repeat mode
/// </summary>
public RepeatMode RepeatMode
{
get => _repeatMode;
private set => this.RaiseAndSetIfChanged(ref _repeatMode, value);
}
/// <summary>
/// Indicates if de-emphasis should be applied
/// </summary>
@@ -180,6 +199,7 @@ namespace RedBookPlayer.Models.Hardware
private PlayerState _playerState;
private DataPlayback _dataPlayback;
private RepeatMode _repeatMode;
private bool _applyDeEmphasis;
private int _volume;
@@ -220,8 +240,9 @@ namespace RedBookPlayer.Models.Hardware
/// </summary>
/// <param name="path">Path to the disc image</param>
/// <param name="options">Options to pass to the optical disc factory</param>
/// <param name="repeatMode">RepeatMode for sound output</param>
/// <param name="autoPlay">True if playback should begin immediately, false otherwise</param>
public void Init(string path, OpticalDiscOptions options, bool autoPlay)
public void Init(string path, OpticalDiscOptions options, RepeatMode repeatMode, bool autoPlay)
{
// Reset initialization
Initialized = false;
@@ -235,7 +256,7 @@ namespace RedBookPlayer.Models.Hardware
_opticalDisc.PropertyChanged += OpticalDiscStateChanged;
// Initialize the sound output
_soundOutput.Init(_opticalDisc, autoPlay);
_soundOutput.Init(_opticalDisc, repeatMode, autoPlay);
if(_soundOutput == null || !_soundOutput.Initialized)
return;
@@ -323,6 +344,23 @@ namespace RedBookPlayer.Models.Hardware
PlayerState = PlayerState.Stopped;
}
/// <summary>
/// Eject the currently loaded disc
/// </summary>
public void Eject()
{
if(_opticalDisc == null || !_opticalDisc.Initialized)
return;
else if(_soundOutput == null)
return;
Stop();
_soundOutput.Eject();
_opticalDisc = null;
PlayerState = PlayerState.NoDisc;
Initialized = false;
}
/// <summary>
/// Move to the next playable track
/// </summary>
@@ -493,6 +531,18 @@ namespace RedBookPlayer.Models.Hardware
#region Helpers
/// <summary>
/// Extract a single track from the image to WAV
/// </summary>
/// <param name="trackNumber"></param>
/// <param name="outputDirectory">Output path to write data to</param
public void ExtractSingleTrackToWav(uint trackNumber, string outputDirectory) => _opticalDisc?.ExtractTrackToWav(trackNumber, outputDirectory);
/// <summary>
/// Extract all tracks from the image to WAV
/// <param name="outputDirectory">Output path to write data to</param
public void ExtractAllTracksToWav(string outputDirectory) => _opticalDisc?.ExtractAllTracksToWav(outputDirectory);
/// <summary>
/// Set data playback method [CompactDisc only]
/// </summary>
@@ -513,6 +563,22 @@ namespace RedBookPlayer.Models.Hardware
compactDisc.LoadHiddenTracks = load;
}
/// <summary>
/// Set repeat mode
/// </summary>
/// <param name="repeatMode">New repeat mode value</param>
public void SetRepeatMode(RepeatMode repeatMode) => _soundOutput?.SetRepeatMode(repeatMode);
/// <summary>
/// Set the value for session handling [CompactDisc only]
/// </summary>
/// <param name="sessionHandling">New session handling value</param>
public void SetSessionHandling(SessionHandling sessionHandling)
{
if(_opticalDisc is CompactDisc compactDisc)
compactDisc.SessionHandling = sessionHandling;
}
/// <summary>
/// Update the player from the current OpticalDisc
/// </summary>
@@ -547,6 +613,7 @@ namespace RedBookPlayer.Models.Hardware
private void SoundOutputStateChanged(object sender, PropertyChangedEventArgs e)
{
PlayerState = _soundOutput.PlayerState;
RepeatMode = _soundOutput.RepeatMode;
ApplyDeEmphasis = _soundOutput.ApplyDeEmphasis;
Volume = _soundOutput.Volume;
}

View File

@@ -31,6 +31,15 @@ namespace RedBookPlayer.Models.Hardware
private set => this.RaiseAndSetIfChanged(ref _playerState, value);
}
/// <summary>
/// Indicates the repeat mode
/// </summary>
public RepeatMode RepeatMode
{
get => _repeatMode;
private set => this.RaiseAndSetIfChanged(ref _repeatMode, value);
}
/// <summary>
/// Indicates if de-emphasis should be applied
/// </summary>
@@ -60,6 +69,7 @@ namespace RedBookPlayer.Models.Hardware
private bool _initialized;
private PlayerState _playerState;
private RepeatMode _repeatMode;
private bool _applyDeEmphasis;
private int _volume;
@@ -117,8 +127,9 @@ namespace RedBookPlayer.Models.Hardware
/// Initialize the output with a given image
/// </summary>
/// <param name="opticalDisc">OpticalDisc to load from</param>
/// <param name="repeatMode">RepeatMode for sound output</param>
/// <param name="autoPlay">True if playback should begin immediately, false otherwise</param>
public void Init(OpticalDiscBase opticalDisc, bool autoPlay)
public void Init(OpticalDiscBase opticalDisc, RepeatMode repeatMode, bool autoPlay)
{
// If we have an unusable disc, just return
if(opticalDisc == null || !opticalDisc.Initialized)
@@ -137,6 +148,9 @@ namespace RedBookPlayer.Models.Hardware
// Setup the audio output
SetupAudio();
// Setup the repeat mode
RepeatMode = repeatMode;
// Initialize playback, if necessary
if(autoPlay)
_soundOut.Play();
@@ -149,6 +163,17 @@ namespace RedBookPlayer.Models.Hardware
_source.Start();
}
/// <summary>
/// Reset the current internal state
/// </summary>
public void Reset()
{
_soundOut.Stop();
_opticalDisc = null;
Initialized = false;
PlayerState = PlayerState.NoDisc;
}
/// <summary>
/// Fill the current byte buffer with playable data
/// </summary>
@@ -189,6 +214,11 @@ namespace RedBookPlayer.Models.Hardware
int currentTrack = _opticalDisc.CurrentTrackNumber;
_opticalDisc.SetCurrentSector(_opticalDisc.CurrentSector + (ulong)(_currentSectorReadPosition / _opticalDisc.BytesPerSector));
_currentSectorReadPosition %= _opticalDisc.BytesPerSector;
if(RepeatMode == RepeatMode.None && _opticalDisc.CurrentTrackNumber < currentTrack)
Stop();
else if(RepeatMode == RepeatMode.Single && _opticalDisc.CurrentTrackNumber != currentTrack)
_opticalDisc.LoadTrack(currentTrack);
}
return count;
@@ -229,6 +259,11 @@ namespace RedBookPlayer.Models.Hardware
PlayerState = PlayerState.Stopped;
}
/// <summary>
/// Eject the currently loaded disc
/// </summary>
public void Eject() => Reset();
#endregion
#region Helpers
@@ -239,6 +274,12 @@ namespace RedBookPlayer.Models.Hardware
/// <param name="apply">New de-emphasis status</param>
public void SetDeEmphasis(bool apply) => ApplyDeEmphasis = apply;
/// <summary>
/// Set repeat mode
/// </summary>
/// <param name="repeatMode">New repeat mode value</param>
public void SetRepeatMode(RepeatMode repeatMode) => RepeatMode = repeatMode;
/// <summary>
/// Set the value for the volume
/// </summary>
@@ -253,8 +294,8 @@ namespace RedBookPlayer.Models.Hardware
/// <param name="zeroSectorsAmount">Number of zeroed sectors to concatenate</param>
private void DetermineReadAmount(int count, out ulong sectorsToRead, out ulong zeroSectorsAmount)
{
// Attempt to read 5 more sectors than requested
sectorsToRead = ((ulong)count / (ulong)_opticalDisc.BytesPerSector) + 5;
// Attempt to read 10 more sectors than requested
sectorsToRead = ((ulong)count / (ulong)_opticalDisc.BytesPerSector) + 10;
zeroSectorsAmount = 0;
// Avoid overreads by padding with 0-byte data at the end