mirror of
https://github.com/aaru-dps/RedBookPlayer.git
synced 2025-12-16 19:24:41 +00:00
Merge pull request #46 from mnadareski/mvvm-v2-features
MVVM v2 Feature Work
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
|||||||
[submodule "Aaru"]
|
|
||||||
path = Aaru
|
|
||||||
url = https://github.com/aaru-dps/Aaru.git
|
|
||||||
[submodule "cscore"]
|
[submodule "cscore"]
|
||||||
path = cscore
|
path = cscore
|
||||||
url = https://github.com/sk-zk/cscore.git
|
url = https://github.com/sk-zk/cscore.git
|
||||||
|
|||||||
1
Aaru
1
Aaru
Submodule Aaru deleted from 2a6903f866
@@ -12,8 +12,10 @@
|
|||||||
| --- | ------ |
|
| --- | ------ |
|
||||||
| **F1** | Open Settings Window |
|
| **F1** | Open Settings Window |
|
||||||
| **F2** | Load New Image |
|
| **F2** | Load New Image |
|
||||||
|
| **S** | Save Track(s) |
|
||||||
| **Space** | Toggle Play / Pause |
|
| **Space** | Toggle Play / Pause |
|
||||||
| **Esc** | Stop Playback |
|
| **Esc** | Stop Playback |
|
||||||
|
| **~** | Eject |
|
||||||
| **→** | Next Track |
|
| **→** | Next Track |
|
||||||
| **←** | Previous Track |
|
| **←** | Previous Track |
|
||||||
| **]** | Next Index |
|
| **]** | Next Index |
|
||||||
@@ -25,6 +27,10 @@
|
|||||||
| **M** | Mute |
|
| **M** | Mute |
|
||||||
| **E** | Toggle Emphasis |
|
| **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:
|
For both Volume Up and Volume Down:
|
||||||
- Holding **Ctrl** will move in increments of 2
|
- Holding **Ctrl** will move in increments of 2
|
||||||
- Holding **Shift** will move in increments of 5
|
- Holding **Shift** will move in increments of 5
|
||||||
|
|||||||
@@ -40,6 +40,23 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
PlayerView?.ViewModel?.ExecuteLoad();
|
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
|
// Toggle playback
|
||||||
else if(e.Key == App.Settings.TogglePlaybackKey || e.Key == Key.MediaPlayPause)
|
else if(e.Key == App.Settings.TogglePlaybackKey || e.Key == Key.MediaPlayPause)
|
||||||
{
|
{
|
||||||
@@ -52,6 +69,12 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
PlayerView?.ViewModel?.ExecuteStop();
|
PlayerView?.ViewModel?.ExecuteStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Eject
|
||||||
|
else if(e.Key == App.Settings.EjectKey)
|
||||||
|
{
|
||||||
|
PlayerView?.ViewModel?.ExecuteEject();
|
||||||
|
}
|
||||||
|
|
||||||
// Next Track
|
// Next Track
|
||||||
else if(e.Key == App.Settings.NextTrackKey || e.Key == Key.MediaNextTrack)
|
else if(e.Key == App.Settings.NextTrackKey || e.Key == Key.MediaNextTrack)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,11 +6,9 @@ using System.Linq;
|
|||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using Avalonia.Platform;
|
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using RedBookPlayer.Models;
|
using RedBookPlayer.Models;
|
||||||
@@ -193,6 +191,15 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
private set => this.RaiseAndSetIfChanged(ref _dataPlayback, value);
|
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>
|
/// <summary>
|
||||||
/// Indicates if de-emphasis should be applied
|
/// Indicates if de-emphasis should be applied
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -214,6 +221,7 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
private bool _initialized;
|
private bool _initialized;
|
||||||
private PlayerState _playerState;
|
private PlayerState _playerState;
|
||||||
private DataPlayback _dataPlayback;
|
private DataPlayback _dataPlayback;
|
||||||
|
private RepeatMode _repeatMode;
|
||||||
private bool _applyDeEmphasis;
|
private bool _applyDeEmphasis;
|
||||||
private int _volume;
|
private int _volume;
|
||||||
|
|
||||||
@@ -250,6 +258,11 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ReactiveCommand<Unit, Unit> StopCommand { get; }
|
public ReactiveCommand<Unit, Unit> StopCommand { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command for ejecting the current disc
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveCommand<Unit, Unit> EjectCommand { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Command for moving to the next track
|
/// Command for moving to the next track
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -334,6 +347,7 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
PauseCommand = ReactiveCommand.Create(ExecutePause);
|
PauseCommand = ReactiveCommand.Create(ExecutePause);
|
||||||
TogglePlayPauseCommand = ReactiveCommand.Create(ExecuteTogglePlayPause);
|
TogglePlayPauseCommand = ReactiveCommand.Create(ExecuteTogglePlayPause);
|
||||||
StopCommand = ReactiveCommand.Create(ExecuteStop);
|
StopCommand = ReactiveCommand.Create(ExecuteStop);
|
||||||
|
EjectCommand = ReactiveCommand.Create(ExecuteEject);
|
||||||
NextTrackCommand = ReactiveCommand.Create(ExecuteNextTrack);
|
NextTrackCommand = ReactiveCommand.Create(ExecuteNextTrack);
|
||||||
PreviousTrackCommand = ReactiveCommand.Create(ExecutePreviousTrack);
|
PreviousTrackCommand = ReactiveCommand.Create(ExecutePreviousTrack);
|
||||||
NextIndexCommand = ReactiveCommand.Create(ExecuteNextIndex);
|
NextIndexCommand = ReactiveCommand.Create(ExecuteNextIndex);
|
||||||
@@ -359,15 +373,16 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">Path to the disc image</param>
|
/// <param name="path">Path to the disc image</param>
|
||||||
/// <param name="options">Options to pass to the optical disc factory</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>
|
/// <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
|
// Stop current playback, if necessary
|
||||||
if(PlayerState != PlayerState.NoDisc)
|
if(PlayerState != PlayerState.NoDisc)
|
||||||
ExecuteStop();
|
ExecuteStop();
|
||||||
|
|
||||||
// Attempt to initialize Player
|
// Attempt to initialize Player
|
||||||
_player.Init(path, options, autoPlay);
|
_player.Init(path, options, repeatMode, autoPlay);
|
||||||
if(_player.Initialized)
|
if(_player.Initialized)
|
||||||
{
|
{
|
||||||
_player.PropertyChanged += PlayerStateChanged;
|
_player.PropertyChanged += PlayerStateChanged;
|
||||||
@@ -397,6 +412,11 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void ExecuteStop() => _player?.Stop();
|
public void ExecuteStop() => _player?.Stop();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Eject the currently loaded disc
|
||||||
|
/// </summary>
|
||||||
|
public void ExecuteEject() => _player?.Eject();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Move to the next playable track
|
/// Move to the next playable track
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -578,13 +598,14 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
DataPlayback = App.Settings.DataPlayback,
|
DataPlayback = App.Settings.DataPlayback,
|
||||||
GenerateMissingToc = App.Settings.GenerateMissingTOC,
|
GenerateMissingToc = App.Settings.GenerateMissingTOC,
|
||||||
LoadHiddenTracks = App.Settings.PlayHiddenTracks,
|
LoadHiddenTracks = App.Settings.PlayHiddenTracks,
|
||||||
|
SessionHandling = App.Settings.SessionHandling,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure the context and view model are set
|
// Ensure the context and view model are set
|
||||||
App.PlayerView.DataContext = this;
|
App.PlayerView.DataContext = this;
|
||||||
App.PlayerView.ViewModel = this;
|
App.PlayerView.ViewModel = this;
|
||||||
|
|
||||||
Init(path, options, App.Settings.AutoPlay);
|
Init(path, options, App.Settings.RepeatMode, App.Settings.AutoPlay);
|
||||||
if(Initialized)
|
if(Initialized)
|
||||||
App.MainWindow.Title = "RedBookPlayer - " + path.Split('/').Last().Split('\\').Last();
|
App.MainWindow.Title = "RedBookPlayer - " + path.Split('/').Last().Split('\\').Last();
|
||||||
|
|
||||||
@@ -599,8 +620,23 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
{
|
{
|
||||||
SetDataPlayback(App.Settings.DataPlayback);
|
SetDataPlayback(App.Settings.DataPlayback);
|
||||||
SetLoadHiddenTracks(App.Settings.PlayHiddenTracks);
|
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>
|
/// <summary>
|
||||||
/// Set data playback method [CompactDisc only]
|
/// Set data playback method [CompactDisc only]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -613,6 +649,18 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
/// <param name="load">True to enable loading hidden tracks, false otherwise</param>
|
/// <param name="load">True to enable loading hidden tracks, false otherwise</param>
|
||||||
public void SetLoadHiddenTracks(bool load) => _player?.SetLoadHiddenTracks(load);
|
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>
|
/// <summary>
|
||||||
/// Generate the digit string to be interpreted by the frontend
|
/// Generate the digit string to be interpreted by the frontend
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -754,6 +802,7 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
|
|
||||||
CurrentTrackNumber = _player.CurrentTrackNumber;
|
CurrentTrackNumber = _player.CurrentTrackNumber;
|
||||||
CurrentTrackIndex = _player.CurrentTrackIndex;
|
CurrentTrackIndex = _player.CurrentTrackIndex;
|
||||||
|
CurrentTrackSession = _player.CurrentTrackSession;
|
||||||
CurrentSector = _player.CurrentSector;
|
CurrentSector = _player.CurrentSector;
|
||||||
SectionStartSector = _player.SectionStartSector;
|
SectionStartSector = _player.SectionStartSector;
|
||||||
|
|
||||||
@@ -766,6 +815,7 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
|
|
||||||
PlayerState = _player.PlayerState;
|
PlayerState = _player.PlayerState;
|
||||||
DataPlayback = _player.DataPlayback;
|
DataPlayback = _player.DataPlayback;
|
||||||
|
RepeatMode = _player.RepeatMode;
|
||||||
ApplyDeEmphasis = _player.ApplyDeEmphasis;
|
ApplyDeEmphasis = _player.ApplyDeEmphasis;
|
||||||
Volume = _player.Volume;
|
Volume = _player.Volume;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,18 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public List<DataPlayback> DataPlaybackValues => GenerateDataPlaybackList();
|
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>
|
/// <summary>
|
||||||
/// List of all themes
|
/// List of all themes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -57,6 +69,16 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DataPlayback DataPlayback { get; set; } = DataPlayback.Skip;
|
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>
|
/// <summary>
|
||||||
/// Indicates the default playback volume
|
/// Indicates the default playback volume
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -102,6 +124,11 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Key LoadImageKey { get; set; } = Key.F2;
|
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>
|
/// <summary>
|
||||||
/// Key assigned to toggle play and pause
|
/// Key assigned to toggle play and pause
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -253,6 +280,16 @@ namespace RedBookPlayer.GUI.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private List<Key> GenerateKeyList() => Enum.GetValues(typeof(Key)).Cast<Key>().ToList();
|
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>
|
/// <summary>
|
||||||
/// Generate the list of valid themes
|
/// Generate the list of valid themes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -30,6 +30,16 @@
|
|||||||
<ComboBox Grid.Row="0" Grid.Column="1" Name="DataPlayback" Margin="8,0,0,0" Width="120"
|
<ComboBox Grid.Row="0" Grid.Column="1" Name="DataPlayback" Margin="8,0,0,0" Width="120"
|
||||||
Items="{Binding DataPlaybackValues}" SelectedItem="{Binding DataPlayback, Mode=TwoWay}" />
|
Items="{Binding DataPlaybackValues}" SelectedItem="{Binding DataPlayback, Mode=TwoWay}" />
|
||||||
</WrapPanel>
|
</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">
|
<WrapPanel Margin="0,0,0,16">
|
||||||
<CheckBox IsChecked="{Binding GenerateMissingTOC}" Margin="0,0,8,0"/>
|
<CheckBox IsChecked="{Binding GenerateMissingTOC}" Margin="0,0,8,0"/>
|
||||||
<TextBlock VerticalAlignment="Center">Generate a TOC if the disc is missing one</TextBlock>
|
<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}"
|
Items="{Binding KeyboardList}" SelectedItem="{Binding LoadImageKey, Mode=TwoWay}"
|
||||||
HorizontalAlignment="Right" Margin="8,0,0,0" Width="120"/>
|
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 -->
|
<!-- Toggle Play/Pause -->
|
||||||
<TextBlock Grid.Row="2" Grid.Column="0" Width="120">Toggle Play/Pause</TextBlock>
|
<TextBlock Grid.Row="2" Grid.Column="0" Width="120">Toggle Play/Pause</TextBlock>
|
||||||
<ComboBox Grid.Row="2" Grid.Column="1" Name="TogglePlaybackKeyBind"
|
<ComboBox Grid.Row="2" Grid.Column="1" Name="TogglePlaybackKeyBind"
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Aaru.CommonTypes.Enums;
|
using Aaru.CommonTypes.Enums;
|
||||||
using Aaru.CommonTypes.Interfaces;
|
using Aaru.CommonTypes.Interfaces;
|
||||||
using Aaru.CommonTypes.Structs;
|
using Aaru.CommonTypes.Structs;
|
||||||
using Aaru.Decoders.CD;
|
using Aaru.Decoders.CD;
|
||||||
using Aaru.Helpers;
|
using Aaru.Helpers;
|
||||||
|
using CSCore.Codecs.WAV;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using static Aaru.Decoders.CD.FullTOC;
|
using static Aaru.Decoders.CD.FullTOC;
|
||||||
|
|
||||||
@@ -69,7 +71,8 @@ namespace RedBookPlayer.Models.Discs
|
|||||||
SetTrackFlags(track);
|
SetTrackFlags(track);
|
||||||
|
|
||||||
// If the track is playable, just return
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -102,6 +105,7 @@ namespace RedBookPlayer.Models.Discs
|
|||||||
|
|
||||||
TotalIndexes = cachedTrack.Indexes.Keys.Max();
|
TotalIndexes = cachedTrack.Indexes.Keys.Max();
|
||||||
CurrentTrackIndex = cachedTrack.Indexes.Keys.Min();
|
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/>
|
/// <inheritdoc/>
|
||||||
public override ulong CurrentSector
|
public override ulong CurrentSector
|
||||||
{
|
{
|
||||||
@@ -229,6 +240,11 @@ namespace RedBookPlayer.Models.Discs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool LoadHiddenTracks { get; set; } = false;
|
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 _quadChannel;
|
||||||
private bool _isDataTrack;
|
private bool _isDataTrack;
|
||||||
private bool _copyAllowed;
|
private bool _copyAllowed;
|
||||||
@@ -248,6 +264,11 @@ namespace RedBookPlayer.Models.Discs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private ushort _currentTrackIndex = 0;
|
private ushort _currentTrackIndex = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current track session
|
||||||
|
/// </summary>
|
||||||
|
private ushort _currentTrackSession = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current sector number
|
/// Current sector number
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -274,6 +295,7 @@ namespace RedBookPlayer.Models.Discs
|
|||||||
DataPlayback = options.DataPlayback;
|
DataPlayback = options.DataPlayback;
|
||||||
_generateMissingToc = options.GenerateMissingToc;
|
_generateMissingToc = options.GenerateMissingToc;
|
||||||
LoadHiddenTracks = options.LoadHiddenTracks;
|
LoadHiddenTracks = options.LoadHiddenTracks;
|
||||||
|
SessionHandling = options.SessionHandling;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -417,6 +439,49 @@ namespace RedBookPlayer.Models.Discs
|
|||||||
|
|
||||||
#region Helpers
|
#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 || !(DataPlayback != DataPlayback.Skip || track.TrackType == TrackType.Audio))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get the number of sectors to read
|
||||||
|
uint length = (uint)(track.TrackEndSector - track.TrackStartSector);
|
||||||
|
|
||||||
|
// Read in the track data to a buffer
|
||||||
|
byte[] buffer = 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()))
|
||||||
|
{
|
||||||
|
// TODO: This should also apply de-emphasis as on playback
|
||||||
|
// Should this be configurable? Match the de-emphasis status?
|
||||||
|
|
||||||
|
// 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/>
|
/// <inheritdoc/>
|
||||||
public override void LoadTrack(int trackNumber)
|
public override void LoadTrack(int trackNumber)
|
||||||
{
|
{
|
||||||
@@ -442,14 +507,30 @@ namespace RedBookPlayer.Models.Discs
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override byte[] ReadSectors(uint sectorsToRead)
|
public override byte[] ReadSectors(uint sectorsToRead) => ReadSectors(CurrentSector, sectorsToRead);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read sector data from the base image starting from the specified sector
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startSector">Sector to start at for reading</param>
|
||||||
|
/// <param name="sectorsToRead">Current number of sectors to read</param>
|
||||||
|
/// <returns>Byte array representing the read sectors, if possible</returns>
|
||||||
|
private byte[] ReadSectors(ulong startSector, uint sectorsToRead)
|
||||||
{
|
{
|
||||||
if(TrackType == TrackType.Audio || DataPlayback == DataPlayback.Play)
|
if(TrackType == TrackType.Audio || DataPlayback == DataPlayback.Play)
|
||||||
return base.ReadSectors(sectorsToRead);
|
{
|
||||||
|
return _image.ReadSectors(startSector, sectorsToRead);
|
||||||
|
}
|
||||||
else if(DataPlayback == DataPlayback.Blank)
|
else if(DataPlayback == DataPlayback.Blank)
|
||||||
return new byte[sectorsToRead * BytesPerSector];
|
{
|
||||||
|
byte[] sectors = _image.ReadSectors(startSector, sectorsToRead);
|
||||||
|
Array.Clear(sectors, 0, sectors.Length);
|
||||||
|
return sectors;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return new byte[0];
|
return new byte[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ namespace RedBookPlayer.Models.Discs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract ushort CurrentTrackIndex { get; protected set; }
|
public abstract ushort CurrentTrackIndex { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current track session
|
||||||
|
/// </summary>
|
||||||
|
public abstract ushort CurrentTrackSession { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current sector number
|
/// Current sector number
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -122,6 +127,19 @@ namespace RedBookPlayer.Models.Discs
|
|||||||
|
|
||||||
#region Helpers
|
#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>
|
/// <summary>
|
||||||
/// Load the desired track, if possible
|
/// Load the desired track, if possible
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ namespace RedBookPlayer.Models.Discs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool LoadHiddenTracks { get; set; } = false;
|
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
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,4 +46,41 @@ namespace RedBookPlayer.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Playing,
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
58
RedBookPlayer.Models/Hardware/FilterStage.cs
Normal file
58
RedBookPlayer.Models/Hardware/FilterStage.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using NWaves.Audio;
|
||||||
|
using NWaves.Filters.BiQuad;
|
||||||
|
|
||||||
|
namespace RedBookPlayer.Models.Hardware
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Output stage that represents all filters on the audio
|
||||||
|
/// </summary>
|
||||||
|
public class FilterStage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Left channel de-emphasis filter
|
||||||
|
/// </summary>
|
||||||
|
private BiQuadFilter _deEmphasisFilterLeft;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Right channel de-emphasis filter
|
||||||
|
/// </summary>
|
||||||
|
private BiQuadFilter _deEmphasisFilterRight;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process audio data with internal filters
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="audioData">Audio data to process</param>
|
||||||
|
public void ProcessAudioData(byte[] audioData)
|
||||||
|
{
|
||||||
|
float[][] floatAudioData = new float[2][];
|
||||||
|
floatAudioData[0] = new float[audioData.Length / 4];
|
||||||
|
floatAudioData[1] = new float[audioData.Length / 4];
|
||||||
|
ByteConverter.ToFloats16Bit(audioData, floatAudioData);
|
||||||
|
|
||||||
|
for(int i = 0; i < floatAudioData[0].Length; i++)
|
||||||
|
{
|
||||||
|
floatAudioData[0][i] = _deEmphasisFilterLeft.Process(floatAudioData[0][i]);
|
||||||
|
floatAudioData[1][i] = _deEmphasisFilterRight.Process(floatAudioData[1][i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteConverter.FromFloats16Bit(floatAudioData, audioData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets or resets the output filters
|
||||||
|
/// </summary>
|
||||||
|
public void SetupFilters()
|
||||||
|
{
|
||||||
|
if(_deEmphasisFilterLeft == null)
|
||||||
|
{
|
||||||
|
_deEmphasisFilterLeft = new DeEmphasisFilter();
|
||||||
|
_deEmphasisFilterRight = new DeEmphasisFilter();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_deEmphasisFilterLeft.Reset();
|
||||||
|
_deEmphasisFilterRight.Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,15 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
private set => this.RaiseAndSetIfChanged(ref _currentTrackIndex, value);
|
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>
|
/// <summary>
|
||||||
/// Current sector number
|
/// Current sector number
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -129,6 +138,7 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
|
|
||||||
private int _currentTrackNumber;
|
private int _currentTrackNumber;
|
||||||
private ushort _currentTrackIndex;
|
private ushort _currentTrackIndex;
|
||||||
|
private ushort _currentTrackSession;
|
||||||
private ulong _currentSector;
|
private ulong _currentSector;
|
||||||
private ulong _sectionStartSector;
|
private ulong _sectionStartSector;
|
||||||
|
|
||||||
@@ -160,6 +170,15 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
private set => this.RaiseAndSetIfChanged(ref _dataPlayback, value);
|
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>
|
/// <summary>
|
||||||
/// Indicates if de-emphasis should be applied
|
/// Indicates if de-emphasis should be applied
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -180,6 +199,7 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
|
|
||||||
private PlayerState _playerState;
|
private PlayerState _playerState;
|
||||||
private DataPlayback _dataPlayback;
|
private DataPlayback _dataPlayback;
|
||||||
|
private RepeatMode _repeatMode;
|
||||||
private bool _applyDeEmphasis;
|
private bool _applyDeEmphasis;
|
||||||
private int _volume;
|
private int _volume;
|
||||||
|
|
||||||
@@ -220,8 +240,9 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">Path to the disc image</param>
|
/// <param name="path">Path to the disc image</param>
|
||||||
/// <param name="options">Options to pass to the optical disc factory</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>
|
/// <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
|
// Reset initialization
|
||||||
Initialized = false;
|
Initialized = false;
|
||||||
@@ -235,7 +256,7 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
_opticalDisc.PropertyChanged += OpticalDiscStateChanged;
|
_opticalDisc.PropertyChanged += OpticalDiscStateChanged;
|
||||||
|
|
||||||
// Initialize the sound output
|
// Initialize the sound output
|
||||||
_soundOutput.Init(_opticalDisc, autoPlay);
|
_soundOutput.Init(_opticalDisc, repeatMode, autoPlay);
|
||||||
if(_soundOutput == null || !_soundOutput.Initialized)
|
if(_soundOutput == null || !_soundOutput.Initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -323,6 +344,23 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
PlayerState = PlayerState.Stopped;
|
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>
|
/// <summary>
|
||||||
/// Move to the next playable track
|
/// Move to the next playable track
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -493,6 +531,18 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
|
|
||||||
#region Helpers
|
#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>
|
/// <summary>
|
||||||
/// Set data playback method [CompactDisc only]
|
/// Set data playback method [CompactDisc only]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -513,6 +563,22 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
compactDisc.LoadHiddenTracks = load;
|
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>
|
/// <summary>
|
||||||
/// Update the player from the current OpticalDisc
|
/// Update the player from the current OpticalDisc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -547,6 +613,7 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
private void SoundOutputStateChanged(object sender, PropertyChangedEventArgs e)
|
private void SoundOutputStateChanged(object sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
PlayerState = _soundOutput.PlayerState;
|
PlayerState = _soundOutput.PlayerState;
|
||||||
|
RepeatMode = _soundOutput.RepeatMode;
|
||||||
ApplyDeEmphasis = _soundOutput.ApplyDeEmphasis;
|
ApplyDeEmphasis = _soundOutput.ApplyDeEmphasis;
|
||||||
Volume = _soundOutput.Volume;
|
Volume = _soundOutput.Volume;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CSCore.SoundOut;
|
using CSCore.SoundOut;
|
||||||
using NWaves.Audio;
|
using NWaves.Audio;
|
||||||
using NWaves.Filters.BiQuad;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using RedBookPlayer.Models.Discs;
|
using RedBookPlayer.Models.Discs;
|
||||||
|
|
||||||
@@ -31,6 +30,15 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
private set => this.RaiseAndSetIfChanged(ref _playerState, value);
|
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>
|
/// <summary>
|
||||||
/// Indicates if de-emphasis should be applied
|
/// Indicates if de-emphasis should be applied
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -60,6 +68,7 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
|
|
||||||
private bool _initialized;
|
private bool _initialized;
|
||||||
private PlayerState _playerState;
|
private PlayerState _playerState;
|
||||||
|
private RepeatMode _repeatMode;
|
||||||
private bool _applyDeEmphasis;
|
private bool _applyDeEmphasis;
|
||||||
private int _volume;
|
private int _volume;
|
||||||
|
|
||||||
@@ -86,14 +95,9 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
private ALSoundOut _soundOut;
|
private ALSoundOut _soundOut;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Left channel de-emphasis filter
|
/// Filtering stage for audio output
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private BiQuadFilter _deEmphasisFilterLeft;
|
private FilterStage _filterStage;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Right channel de-emphasis filter
|
|
||||||
/// </summary>
|
|
||||||
private BiQuadFilter _deEmphasisFilterRight;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current position in the sector
|
/// Current position in the sector
|
||||||
@@ -111,14 +115,20 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
/// Constructor
|
/// Constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="defaultVolume">Default volume between 0 and 100 to use when starting playback</param>
|
/// <param name="defaultVolume">Default volume between 0 and 100 to use when starting playback</param>
|
||||||
public SoundOutput(int defaultVolume = 100) => Volume = defaultVolume;
|
public SoundOutput(int defaultVolume = 100)
|
||||||
|
{
|
||||||
|
Volume = defaultVolume;
|
||||||
|
_filterStage = new FilterStage();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize the output with a given image
|
/// Initialize the output with a given image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="opticalDisc">OpticalDisc to load from</param>
|
/// <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>
|
/// <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 we have an unusable disc, just return
|
||||||
if(opticalDisc == null || !opticalDisc.Initialized)
|
if(opticalDisc == null || !opticalDisc.Initialized)
|
||||||
@@ -132,11 +142,14 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
ApplyDeEmphasis = compactDisc.TrackHasEmphasis;
|
ApplyDeEmphasis = compactDisc.TrackHasEmphasis;
|
||||||
|
|
||||||
// Setup de-emphasis filters
|
// Setup de-emphasis filters
|
||||||
SetupFilters();
|
_filterStage.SetupFilters();
|
||||||
|
|
||||||
// Setup the audio output
|
// Setup the audio output
|
||||||
SetupAudio();
|
SetupAudio();
|
||||||
|
|
||||||
|
// Setup the repeat mode
|
||||||
|
RepeatMode = repeatMode;
|
||||||
|
|
||||||
// Initialize playback, if necessary
|
// Initialize playback, if necessary
|
||||||
if(autoPlay)
|
if(autoPlay)
|
||||||
_soundOut.Play();
|
_soundOut.Play();
|
||||||
@@ -149,6 +162,17 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
_source.Start();
|
_source.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reset the current internal state
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_soundOut.Stop();
|
||||||
|
_opticalDisc = null;
|
||||||
|
Initialized = false;
|
||||||
|
PlayerState = PlayerState.NoDisc;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fill the current byte buffer with playable data
|
/// Fill the current byte buffer with playable data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -189,6 +213,11 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
int currentTrack = _opticalDisc.CurrentTrackNumber;
|
int currentTrack = _opticalDisc.CurrentTrackNumber;
|
||||||
_opticalDisc.SetCurrentSector(_opticalDisc.CurrentSector + (ulong)(_currentSectorReadPosition / _opticalDisc.BytesPerSector));
|
_opticalDisc.SetCurrentSector(_opticalDisc.CurrentSector + (ulong)(_currentSectorReadPosition / _opticalDisc.BytesPerSector));
|
||||||
_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;
|
return count;
|
||||||
@@ -229,6 +258,11 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
PlayerState = PlayerState.Stopped;
|
PlayerState = PlayerState.Stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Eject the currently loaded disc
|
||||||
|
/// </summary>
|
||||||
|
public void Eject() => Reset();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Helpers
|
#region Helpers
|
||||||
@@ -239,6 +273,12 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
/// <param name="apply">New de-emphasis status</param>
|
/// <param name="apply">New de-emphasis status</param>
|
||||||
public void SetDeEmphasis(bool apply) => ApplyDeEmphasis = apply;
|
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>
|
/// <summary>
|
||||||
/// Set the value for the volume
|
/// Set the value for the volume
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -253,8 +293,8 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
/// <param name="zeroSectorsAmount">Number of zeroed sectors to concatenate</param>
|
/// <param name="zeroSectorsAmount">Number of zeroed sectors to concatenate</param>
|
||||||
private void DetermineReadAmount(int count, out ulong sectorsToRead, out ulong zeroSectorsAmount)
|
private void DetermineReadAmount(int count, out ulong sectorsToRead, out ulong zeroSectorsAmount)
|
||||||
{
|
{
|
||||||
// Attempt to read 5 more sectors than requested
|
// Attempt to read 10 more sectors than requested
|
||||||
sectorsToRead = ((ulong)count / (ulong)_opticalDisc.BytesPerSector) + 5;
|
sectorsToRead = ((ulong)count / (ulong)_opticalDisc.BytesPerSector) + 10;
|
||||||
zeroSectorsAmount = 0;
|
zeroSectorsAmount = 0;
|
||||||
|
|
||||||
// Avoid overreads by padding with 0-byte data at the end
|
// Avoid overreads by padding with 0-byte data at the end
|
||||||
@@ -268,26 +308,6 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process de-emphasis of audio data
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="audioData">Audio data to process</param>
|
|
||||||
private void ProcessDeEmphasis(byte[] audioData)
|
|
||||||
{
|
|
||||||
float[][] floatAudioData = new float[2][];
|
|
||||||
floatAudioData[0] = new float[audioData.Length / 4];
|
|
||||||
floatAudioData[1] = new float[audioData.Length / 4];
|
|
||||||
ByteConverter.ToFloats16Bit(audioData, floatAudioData);
|
|
||||||
|
|
||||||
for(int i = 0; i < floatAudioData[0].Length; i++)
|
|
||||||
{
|
|
||||||
floatAudioData[0][i] = _deEmphasisFilterLeft.Process(floatAudioData[0][i]);
|
|
||||||
floatAudioData[1][i] = _deEmphasisFilterRight.Process(floatAudioData[1][i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteConverter.FromFloats16Bit(floatAudioData, audioData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read the requested amount of data from an input
|
/// Read the requested amount of data from an input
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -335,28 +355,11 @@ namespace RedBookPlayer.Models.Hardware
|
|||||||
|
|
||||||
// Apply de-emphasis filtering, only if enabled
|
// Apply de-emphasis filtering, only if enabled
|
||||||
if(ApplyDeEmphasis)
|
if(ApplyDeEmphasis)
|
||||||
ProcessDeEmphasis(audioDataSegment);
|
_filterStage.ProcessAudioData(audioDataSegment);
|
||||||
|
|
||||||
return audioDataSegment;
|
return audioDataSegment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets or resets the de-emphasis filters
|
|
||||||
/// </summary>
|
|
||||||
private void SetupFilters()
|
|
||||||
{
|
|
||||||
if(_deEmphasisFilterLeft == null)
|
|
||||||
{
|
|
||||||
_deEmphasisFilterLeft = new DeEmphasisFilter();
|
|
||||||
_deEmphasisFilterRight = new DeEmphasisFilter();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_deEmphasisFilterLeft.Reset();
|
|
||||||
_deEmphasisFilterRight.Reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets or resets the audio playback objects
|
/// Sets or resets the audio playback objects
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Aaru.CommonTypes" Version="5.3.0" />
|
||||||
|
<PackageReference Include="Aaru.Decoders" Version="5.3.0" />
|
||||||
|
<PackageReference Include="Aaru.Images" Version="5.3.0" />
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="0.9.12" />
|
<PackageReference Include="Avalonia.ReactiveUI" Version="0.9.12" />
|
||||||
<PackageReference Include="NWaves" Version="0.9.4" />
|
<PackageReference Include="NWaves" Version="0.9.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Aaru\Aaru.Images\Aaru.Images.csproj" />
|
|
||||||
<ProjectReference Include="..\Aaru\Aaru.CommonTypes\Aaru.CommonTypes.csproj" />
|
|
||||||
<ProjectReference Include="..\Aaru\Aaru.Decoders\Aaru.Decoders.csproj" />
|
|
||||||
<ProjectReference Include="..\cscore\CSCore\CSCore.csproj" />
|
<ProjectReference Include="..\cscore\CSCore\CSCore.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -9,30 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cscore", "cscore", "{9A3712
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSCore", "cscore\CSCore\CSCore.csproj", "{C81E7637-D25A-4545-8E27-4D83D973F4DC}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSCore", "cscore\CSCore\CSCore.csproj", "{C81E7637-D25A-4545-8E27-4D83D973F4DC}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Aaru", "Aaru", "{BAC4D43B-B6B0-495F-A147-1D4761D60134}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aaru.CommonTypes", "Aaru\Aaru.CommonTypes\Aaru.CommonTypes.csproj", "{F2B84194-26EB-4227-B1C5-6602517E85AE}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aaru.Decoders", "Aaru\Aaru.Decoders\Aaru.Decoders.csproj", "{0BEB3088-B634-4289-AE17-CDF2D25D00D5}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aaru.Helpers", "Aaru\Aaru.Helpers\Aaru.Helpers.csproj", "{F8BDF57B-1571-4CD0-84B3-B422088D359A}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aaru.Images", "Aaru\Aaru.Images\Aaru.Images.csproj", "{74032CBC-339B-42F3-AF6F-E96C261F3E6A}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aaru.Console", "Aaru\Aaru.Console\Aaru.Console.csproj", "{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aaru.Checksums", "Aaru\Aaru.Checksums\Aaru.Checksums.csproj", "{CC48B324-A532-4A45-87A6-6F91F7141E8D}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aaru.Compression", "Aaru\Aaru.Compression\Aaru.Compression.csproj", "{858398D1-7321-4763-8BAB-56BBFEC74E29}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aaru.Filters", "Aaru\Aaru.Filters\Aaru.Filters.csproj", "{D571B8EF-903D-4353-BDD5-B834F9F029EF}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cuetools.net", "cuetools.net", "{7B180FCA-A2BB-48C8-AF36-2300C033C476}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CUETools.Codecs", "Aaru\cuetools.net\CUETools.Codecs\CUETools.Codecs.csproj", "{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CUETools.Codecs.Flake", "Aaru\cuetools.net\CUETools.Codecs.Flake\CUETools.Codecs.Flake.csproj", "{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0531C157-8111-4BC9-8C65-A2FDDB0C96FD}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0531C157-8111-4BC9-8C65-A2FDDB0C96FD}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
build.bat = build.bat
|
build.bat = build.bat
|
||||||
@@ -76,126 +52,6 @@ Global
|
|||||||
{C81E7637-D25A-4545-8E27-4D83D973F4DC}.Release|x64.Build.0 = Release|Any CPU
|
{C81E7637-D25A-4545-8E27-4D83D973F4DC}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{C81E7637-D25A-4545-8E27-4D83D973F4DC}.Release|x86.ActiveCfg = Release|Any CPU
|
{C81E7637-D25A-4545-8E27-4D83D973F4DC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{C81E7637-D25A-4545-8E27-4D83D973F4DC}.Release|x86.Build.0 = Release|Any CPU
|
{C81E7637-D25A-4545-8E27-4D83D973F4DC}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{462A3B8E-A5D4-4539-8469-1647B47AB2A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{462A3B8E-A5D4-4539-8469-1647B47AB2A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{462A3B8E-A5D4-4539-8469-1647B47AB2A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{462A3B8E-A5D4-4539-8469-1647B47AB2A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{462A3B8E-A5D4-4539-8469-1647B47AB2A8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
{462A3B8E-A5D4-4539-8469-1647B47AB2A8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
@@ -214,17 +70,6 @@ Global
|
|||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{C81E7637-D25A-4545-8E27-4D83D973F4DC} = {9A371299-4C59-4E46-9C3B-4FE024017491}
|
{C81E7637-D25A-4545-8E27-4D83D973F4DC} = {9A371299-4C59-4E46-9C3B-4FE024017491}
|
||||||
{F2B84194-26EB-4227-B1C5-6602517E85AE} = {BAC4D43B-B6B0-495F-A147-1D4761D60134}
|
|
||||||
{0BEB3088-B634-4289-AE17-CDF2D25D00D5} = {BAC4D43B-B6B0-495F-A147-1D4761D60134}
|
|
||||||
{F8BDF57B-1571-4CD0-84B3-B422088D359A} = {BAC4D43B-B6B0-495F-A147-1D4761D60134}
|
|
||||||
{74032CBC-339B-42F3-AF6F-E96C261F3E6A} = {BAC4D43B-B6B0-495F-A147-1D4761D60134}
|
|
||||||
{CCAA7AFE-C094-4D82-A66D-630DE8A3F545} = {BAC4D43B-B6B0-495F-A147-1D4761D60134}
|
|
||||||
{CC48B324-A532-4A45-87A6-6F91F7141E8D} = {BAC4D43B-B6B0-495F-A147-1D4761D60134}
|
|
||||||
{858398D1-7321-4763-8BAB-56BBFEC74E29} = {BAC4D43B-B6B0-495F-A147-1D4761D60134}
|
|
||||||
{D571B8EF-903D-4353-BDD5-B834F9F029EF} = {BAC4D43B-B6B0-495F-A147-1D4761D60134}
|
|
||||||
{7B180FCA-A2BB-48C8-AF36-2300C033C476} = {BAC4D43B-B6B0-495F-A147-1D4761D60134}
|
|
||||||
{8F4AD79C-D5E5-44C4-9F03-B0DF4EE8BBA0} = {7B180FCA-A2BB-48C8-AF36-2300C033C476}
|
|
||||||
{ED8E11B7-786F-4EFF-9E4C-B937B7A2DE89} = {7B180FCA-A2BB-48C8-AF36-2300C033C476}
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {6BBF5459-C634-4145-961C-04EBE90FE66B}
|
SolutionGuid = {6BBF5459-C634-4145-961C-04EBE90FE66B}
|
||||||
|
|||||||
Reference in New Issue
Block a user