284 lines
6.9 KiB
C#
284 lines
6.9 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
|
|
using BizHawk.Common.BufferExtensions;
|
|
using BizHawk.Client.Common;
|
|
|
|
using BizHawk.Emulation.Cores.PCEngine;
|
|
using BizHawk.Emulation.Common.Components;
|
|
using BizHawk.Emulation.Common;
|
|
|
|
using ICSharpCode.SharpZipLib.Zip;
|
|
|
|
namespace BizHawk.Client.EmuHawk
|
|
{
|
|
public partial class PCESoundDebugger : Form, IToolFormAutoConfig
|
|
{
|
|
[RequiredService]
|
|
private PCEngine _pce { get; set; }
|
|
|
|
public PCESoundDebugger()
|
|
{
|
|
InitializeComponent();
|
|
|
|
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
|
SetStyle(ControlStyles.UserPaint, true);
|
|
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
|
}
|
|
|
|
byte[] waveformTemp = new byte[32 * 2];
|
|
|
|
protected override void OnShown(EventArgs e)
|
|
{
|
|
for (int i = 0; i < lvChEn.Items.Count; i++)
|
|
lvChEn.Items[i].Checked = true;
|
|
base.OnShown(e);
|
|
}
|
|
|
|
public void UpdateValues()
|
|
{
|
|
foreach (var entry in PSGEntries)
|
|
{
|
|
entry.wasactive = entry.active;
|
|
entry.active = false;
|
|
}
|
|
|
|
bool sync = false;
|
|
lvPsgWaveforms.BeginUpdate();
|
|
lvChannels.BeginUpdate();
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
var ch = _pce.PSG.Channels[i];
|
|
|
|
//these conditions mean a sample isnt playing
|
|
if (!ch.Enabled)
|
|
{
|
|
lvChannels.Items[i].SubItems[1].Text = "-";
|
|
lvChannels.Items[i].SubItems[2].Text = "-";
|
|
lvChannels.Items[i].SubItems[3].Text = "(disabled)";
|
|
goto DEAD;
|
|
}
|
|
if (ch.DDA)
|
|
{
|
|
lvChannels.Items[i].SubItems[1].Text = "-";
|
|
lvChannels.Items[i].SubItems[2].Text = "-";
|
|
lvChannels.Items[i].SubItems[3].Text = "(DDA)";
|
|
goto DEAD;
|
|
}
|
|
lvChannels.Items[i].SubItems[1].Text = ch.Volume.ToString();
|
|
lvChannels.Items[i].SubItems[2].Text = ch.Frequency.ToString();
|
|
if (ch.NoiseChannel)
|
|
{
|
|
lvChannels.Items[i].SubItems[3].Text = "(noise)";
|
|
goto DEAD;
|
|
}
|
|
|
|
if (ch.Volume == 0) goto DEAD;
|
|
|
|
lvChannels.Items[i].SubItems[3].Text = "-";
|
|
|
|
//ok, a sample is playing. copy out the waveform
|
|
short[] waveform = (short[])ch.Wave.Clone();
|
|
//hash it
|
|
var ms = new MemoryStream(waveformTemp);
|
|
var bw = new BinaryWriter(ms);
|
|
foreach (var s in waveform)
|
|
bw.Write(s);
|
|
bw.Flush();
|
|
string md5 = waveformTemp.HashMD5();
|
|
|
|
if (!PSGEntryTable.ContainsKey(md5))
|
|
{
|
|
var entry = new PSGEntry()
|
|
{
|
|
hash = md5,
|
|
name = md5,
|
|
waveform = waveform,
|
|
active = true,
|
|
hitcount = 1,
|
|
index = PSGEntries.Count
|
|
};
|
|
PSGEntries.Add(entry);
|
|
PSGEntryTable[md5] = entry;
|
|
sync = true;
|
|
LastSamples[i] = entry;
|
|
}
|
|
else
|
|
{
|
|
PSGEntry entry = PSGEntryTable[md5];
|
|
entry.active = true;
|
|
|
|
//are we playing the same sample as before?
|
|
if (LastSamples[i] == entry) { }
|
|
else
|
|
//if (!entry.wasactive)
|
|
{
|
|
LastSamples[i] = entry;
|
|
entry.hitcount++;
|
|
if (entry.index < lvPsgWaveforms.Items.Count)
|
|
lvPsgWaveforms.Items[entry.index].SubItems[1].Text = entry.hitcount.ToString();
|
|
else
|
|
sync = true;
|
|
}
|
|
}
|
|
|
|
lvChannels.Items[i].SubItems[3].Text = PSGEntryTable[md5].name;
|
|
|
|
continue;
|
|
|
|
DEAD:
|
|
LastSamples[i] = null;
|
|
}
|
|
|
|
if (sync)
|
|
SyncLists();
|
|
lvPsgWaveforms.EndUpdate();
|
|
lvChannels.EndUpdate();
|
|
}
|
|
|
|
public void FastUpdate()
|
|
{
|
|
// Todo
|
|
}
|
|
|
|
class PSGEntry
|
|
{
|
|
public int index;
|
|
public bool active, wasactive;
|
|
public int hitcount;
|
|
public string hash;
|
|
public string name;
|
|
public short[] waveform;
|
|
}
|
|
|
|
PSGEntry[] LastSamples = new PSGEntry[8];
|
|
List<PSGEntry> PSGEntries = new List<PSGEntry>();
|
|
Dictionary<string, PSGEntry> PSGEntryTable = new Dictionary<string, PSGEntry>();
|
|
|
|
public void Restart()
|
|
{
|
|
}
|
|
|
|
public bool AskSaveChanges()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public bool UpdateBefore
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
|
|
//32*16 samples, 16bit, mono, 8khz (but we'll change the sample rate)
|
|
static readonly byte[] emptyWav = new byte[] {
|
|
0x52, 0x49, 0x46, 0x46, 0x24, 0x04, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20,
|
|
0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xE0, 0x2E, 0x00, 0x00, 0xC0, 0x5D, 0x00, 0x00,
|
|
0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x04, 0x00, 0x00,
|
|
};
|
|
|
|
|
|
private void btnExport_Click(object sender, EventArgs e)
|
|
{
|
|
string tmpf = Path.GetTempFileName() + ".zip";
|
|
using (var stream = new FileStream(tmpf, FileMode.Create, FileAccess.Write, FileShare.Read))
|
|
{
|
|
var zip = new ZipOutputStream(stream)
|
|
{
|
|
IsStreamOwner = false,
|
|
UseZip64 = UseZip64.Off
|
|
};
|
|
|
|
foreach (var entry in PSGEntries)
|
|
{
|
|
var ze = new ZipEntry(entry.name + ".wav") { CompressionMethod = CompressionMethod.Deflated };
|
|
zip.PutNextEntry(ze);
|
|
var ms = new MemoryStream();
|
|
var bw = new BinaryWriter(ms);
|
|
bw.Write(emptyWav, 0, emptyWav.Length);
|
|
ms.Position = 0x18; //samplerate and avgbytespersecond
|
|
bw.Write(20000);
|
|
bw.Write(20000 * 2);
|
|
bw.Flush();
|
|
ms.Position = 0x2C;
|
|
for (int i = 0; i < 32; i++)
|
|
for (int j = 0; j < 16; j++)
|
|
bw.Write(entry.waveform[i]);
|
|
bw.Flush();
|
|
var buf = ms.GetBuffer();
|
|
zip.Write(buf, 0, (int)ms.Length);
|
|
zip.Flush();
|
|
zip.CloseEntry();
|
|
}
|
|
zip.Close();
|
|
stream.Flush();
|
|
}
|
|
System.Diagnostics.Process.Start(tmpf);
|
|
}
|
|
|
|
class ZipDataSource : IStaticDataSource
|
|
{
|
|
public ZipDataSource(byte[] data) { this.data = data; }
|
|
byte[] data;
|
|
public Stream GetSource() { return new MemoryStream(data); }
|
|
}
|
|
|
|
private void btnReset_Click(object sender, EventArgs e)
|
|
{
|
|
PSGEntryTable.Clear();
|
|
PSGEntries.Clear();
|
|
for (int i = 0; i < 8; i++) LastSamples[i] = null;
|
|
SyncLists();
|
|
}
|
|
|
|
void SyncLists()
|
|
{
|
|
lvPsgWaveforms.Items.Clear();
|
|
foreach (var entry in PSGEntries)
|
|
{
|
|
var lvi = new ListViewItem(entry.name);
|
|
lvi.SubItems.Add(entry.hitcount.ToString());
|
|
lvPsgWaveforms.Items.Add(lvi);
|
|
}
|
|
}
|
|
|
|
private void lvPsgWaveforms_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (e.KeyCode == Keys.F2 && lvPsgWaveforms.SelectedItems.Count > 0)
|
|
{
|
|
lvPsgWaveforms.SelectedItems[0].BeginEdit();
|
|
}
|
|
}
|
|
|
|
private void lvPsgWaveforms_ItemActivate(object sender, EventArgs e)
|
|
{
|
|
|
|
}
|
|
|
|
private void lvPsgWaveforms_AfterLabelEdit(object sender, LabelEditEventArgs e)
|
|
{
|
|
var entry = PSGEntries[e.Item];
|
|
entry.name = e.Label;
|
|
}
|
|
|
|
private void lvChEn_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
|
|
{
|
|
|
|
}
|
|
|
|
private void lvChEn_ItemChecked(object sender, ItemCheckedEventArgs e)
|
|
{
|
|
for (int i = 0; i < 6; i++)
|
|
_pce.PSG.UserMute[i] = !lvChEn.Items[i].Checked;
|
|
}
|
|
}
|
|
}
|