2017-08-20 19:47:05 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections;
|
2017-08-03 14:34:40 +00:00
|
|
|
|
using System.Collections.Generic;
|
2017-08-20 19:47:05 +00:00
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Runtime.CompilerServices;
|
2017-08-03 14:34:40 +00:00
|
|
|
|
using Emux.GameBoy.Audio;
|
|
|
|
|
using NAudio.Wave;
|
|
|
|
|
|
2018-07-07 21:26:14 +00:00
|
|
|
|
namespace Emux.NAudio
|
2017-08-03 14:34:40 +00:00
|
|
|
|
{
|
2018-07-07 21:26:14 +00:00
|
|
|
|
public class GameBoyNAudioMixer : IWaveProvider, INotifyPropertyChanged
|
2017-08-03 14:34:40 +00:00
|
|
|
|
{
|
2017-08-20 19:47:05 +00:00
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
|
|
2017-08-03 14:34:40 +00:00
|
|
|
|
private readonly MixingWaveProvider32 _mixer = new MixingWaveProvider32();
|
2017-08-20 19:47:05 +00:00
|
|
|
|
private bool _enabled = true;
|
|
|
|
|
private WaveFileWriter _writer;
|
|
|
|
|
private bool _isRecording;
|
2017-08-03 14:34:40 +00:00
|
|
|
|
|
2018-07-07 21:26:14 +00:00
|
|
|
|
public GameBoyNAudioMixer()
|
2017-08-03 14:34:40 +00:00
|
|
|
|
{
|
|
|
|
|
Channels = new List<NAudioChannelOutput>
|
|
|
|
|
{
|
2017-08-20 19:47:05 +00:00
|
|
|
|
new NAudioChannelOutput(this, "Square + Sweep"),
|
|
|
|
|
new NAudioChannelOutput(this, "Square"),
|
|
|
|
|
new NAudioChannelOutput(this, "Wave"),
|
|
|
|
|
new NAudioChannelOutput(this, "Noise"),
|
2017-08-03 14:34:40 +00:00
|
|
|
|
}.AsReadOnly();
|
|
|
|
|
|
|
|
|
|
foreach (var channel in Channels)
|
|
|
|
|
_mixer.AddInputStream(channel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public WaveFormat WaveFormat
|
|
|
|
|
{
|
|
|
|
|
get { return _mixer.WaveFormat; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IList<NAudioChannelOutput> Channels
|
|
|
|
|
{
|
|
|
|
|
get;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-20 19:47:05 +00:00
|
|
|
|
public bool IsRecording
|
|
|
|
|
{
|
|
|
|
|
get { return _isRecording; }
|
|
|
|
|
private set
|
|
|
|
|
{
|
|
|
|
|
if (_isRecording != value)
|
|
|
|
|
{
|
|
|
|
|
_isRecording = value;
|
|
|
|
|
OnPropertyChanged(nameof(IsRecording));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool Enabled
|
|
|
|
|
{
|
|
|
|
|
get { return _enabled; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_enabled != value)
|
|
|
|
|
{
|
|
|
|
|
_enabled = value;
|
|
|
|
|
OnPropertyChanged(nameof(Enabled));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 14:34:40 +00:00
|
|
|
|
public int Read(byte[] buffer, int offset, int count)
|
|
|
|
|
{
|
|
|
|
|
_mixer.Read(buffer, offset, count);
|
2017-08-20 19:47:05 +00:00
|
|
|
|
if (!Enabled)
|
|
|
|
|
Array.Clear(buffer, offset, count);
|
|
|
|
|
|
|
|
|
|
lock (this)
|
|
|
|
|
{
|
|
|
|
|
_writer?.Write(buffer, offset, count);
|
|
|
|
|
}
|
2017-08-03 14:34:40 +00:00
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Connect(GameBoySpu spu)
|
|
|
|
|
{
|
|
|
|
|
for (var i = 0; i < spu.Channels.Count; i++)
|
2017-09-18 21:57:09 +00:00
|
|
|
|
{
|
|
|
|
|
var channel = spu.Channels[i];
|
|
|
|
|
channel.ChannelOutput = Channels[i];
|
|
|
|
|
channel.ChannelVolume = 0.05f;
|
|
|
|
|
}
|
2017-08-20 19:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void StartRecording(Stream outputStream)
|
|
|
|
|
{
|
|
|
|
|
if (outputStream == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(outputStream));
|
|
|
|
|
|
|
|
|
|
lock (this)
|
2017-08-03 14:34:40 +00:00
|
|
|
|
{
|
2017-08-20 19:47:05 +00:00
|
|
|
|
if (IsRecording)
|
|
|
|
|
throw new InvalidOperationException("Cannot start a recording when a recording is already happening.");
|
|
|
|
|
_writer = new WaveFileWriter(outputStream, WaveFormat);
|
|
|
|
|
IsRecording = true;
|
2017-08-03 14:34:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-20 19:47:05 +00:00
|
|
|
|
|
|
|
|
|
public void StopRecording()
|
|
|
|
|
{
|
|
|
|
|
lock (this)
|
|
|
|
|
{
|
2017-09-16 15:26:09 +00:00
|
|
|
|
if (!IsRecording)
|
2017-08-20 19:47:05 +00:00
|
|
|
|
throw new InvalidOperationException("Cannot stop a recording when a recording is not happening.");
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_writer.Flush();
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_writer.Dispose();
|
|
|
|
|
_writer = null;
|
|
|
|
|
IsRecording = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual void OnPropertyChanged(string propertyName = null)
|
|
|
|
|
{
|
|
|
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
|
|
}
|
2017-08-03 14:34:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|