mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-09-12 04:07:32 +08:00
457 lines
14 KiB
C#
457 lines
14 KiB
C#
using CodeWalker.GameFiles;
|
|
using CodeWalker.Utils;
|
|
using FastColoredTextBoxNS;
|
|
using System;
|
|
using System.IO;
|
|
using System.Diagnostics;
|
|
using System.Windows.Forms;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using Range = FastColoredTextBoxNS.Range;
|
|
|
|
namespace CodeWalker.Forms
|
|
{
|
|
public partial class AwcForm : Form
|
|
{
|
|
public AwcFile Awc { get; set; }
|
|
|
|
private string fileName;
|
|
public string FileName
|
|
{
|
|
get { return fileName; }
|
|
set
|
|
{
|
|
fileName = value;
|
|
UpdateFormTitle();
|
|
}
|
|
}
|
|
public string FilePath { get; set; }
|
|
|
|
private bool LoadingXml = false;
|
|
private bool DelayHighlight = false;
|
|
|
|
private AudioPlayer Player = new AudioPlayer();
|
|
|
|
private bool PositionScrolled = false;
|
|
|
|
public AwcForm()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
private void UpdateFormTitle()
|
|
{
|
|
Text = fileName + " - AWC Player - CodeWalker by dexyfex";
|
|
}
|
|
|
|
private void UpdateXmlTextBox(string xml)
|
|
{
|
|
LoadingXml = true;
|
|
XmlTextBox.Text = "";
|
|
XmlTextBox.Language = Language.XML;
|
|
DelayHighlight = false;
|
|
|
|
if (string.IsNullOrEmpty(xml))
|
|
{
|
|
LoadingXml = false;
|
|
return;
|
|
}
|
|
//if (xml.Length > (1048576 * 5))
|
|
//{
|
|
// XmlTextBox.Language = Language.Custom;
|
|
// XmlTextBox.Text = "[XML size > 10MB - Not shown due to performance limitations - Please use an external viewer for this file.]";
|
|
// return;
|
|
//}
|
|
//else
|
|
if (xml.Length > (1024 * 512))
|
|
{
|
|
XmlTextBox.Language = Language.Custom;
|
|
DelayHighlight = true;
|
|
}
|
|
//else
|
|
//{
|
|
// XmlTextBox.Language = Language.XML;
|
|
//}
|
|
|
|
|
|
Cursor = Cursors.WaitCursor;
|
|
|
|
|
|
|
|
XmlTextBox.Text = xml;
|
|
//XmlTextBox.IsChanged = false;
|
|
XmlTextBox.ClearUndo();
|
|
|
|
Cursor = Cursors.Default;
|
|
LoadingXml = false;
|
|
}
|
|
|
|
public void LoadAwc(AwcFile awc)
|
|
{
|
|
Awc = awc;
|
|
DetailsPropertyGrid.SelectedObject = awc;
|
|
|
|
fileName = awc?.Name;
|
|
if (string.IsNullOrEmpty(fileName))
|
|
{
|
|
fileName = awc?.FileEntry?.Name;
|
|
}
|
|
|
|
PlayListView.Items.Clear();
|
|
|
|
float totalLength = 0;
|
|
if (awc.Streams != null)
|
|
{
|
|
var strlist = awc.Streams.ToList();
|
|
strlist.Sort((a, b) => a.Name.CompareTo(b.Name));
|
|
foreach (var audio in strlist)
|
|
{
|
|
var stereo = (audio.ChannelStreams?.Length == 2);
|
|
if ((audio.StreamBlocks != null) && (!stereo)) continue;//don't display multichannel source audios
|
|
var name = audio.Name;
|
|
if (stereo) name = "(Stereo Playback)";
|
|
var item = PlayListView.Items.Add(name);
|
|
item.SubItems.Add(audio.Type);
|
|
item.SubItems.Add(audio.LengthStr);
|
|
item.SubItems.Add(TextUtil.GetBytesReadable(audio.ByteLength));
|
|
item.Tag = audio;
|
|
totalLength += audio.Length;
|
|
}
|
|
}
|
|
|
|
LabelInfo.Text = awc.Streams.Length.ToString() + " track(s), Length: " + TimeSpan.FromSeconds((float)totalLength).ToString("h\\:mm\\:ss");
|
|
UpdateFormTitle();
|
|
}
|
|
|
|
public void LoadXml()
|
|
{
|
|
if (Awc != null)
|
|
{
|
|
var xml = AwcXml.GetXml(Awc);
|
|
UpdateXmlTextBox(xml);
|
|
}
|
|
}
|
|
|
|
private void HTMLSyntaxHighlight(Range range)
|
|
{
|
|
try
|
|
{
|
|
Style BlueStyle = new TextStyle(Brushes.Blue, null, FontStyle.Regular);
|
|
Style RedStyle = new TextStyle(Brushes.Red, null, FontStyle.Regular);
|
|
Style MaroonStyle = new TextStyle(Brushes.Maroon, null, FontStyle.Regular);
|
|
|
|
//clear style of changed range
|
|
range.ClearStyle(BlueStyle, MaroonStyle, RedStyle);
|
|
//tag brackets highlighting
|
|
range.SetStyle(BlueStyle, @"<|/>|</|>");
|
|
//tag name
|
|
range.SetStyle(MaroonStyle, @"<(?<range>[!\w]+)");
|
|
//end of tag
|
|
range.SetStyle(MaroonStyle, @"</(?<range>\w+)>");
|
|
//attributes
|
|
range.SetStyle(RedStyle, @"(?<range>\S+?)='[^']*'|(?<range>\S+)=""[^""]*""|(?<range>\S+)=\S+");
|
|
//attribute values
|
|
range.SetStyle(BlueStyle, @"\S+?=(?<range>'[^']*')|\S+=(?<range>""[^""]*"")|\S+=(?<range>\S+)");
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
|
|
|
|
private void Stop()
|
|
{
|
|
Player.Stop();
|
|
UpdateUI();
|
|
UpdatePlayerButtons();
|
|
}
|
|
|
|
private void Play()
|
|
{
|
|
Stop();
|
|
|
|
if (PlayListView.SelectedItems.Count == 1)
|
|
{
|
|
var item = PlayListView.SelectedItems[0];
|
|
var audio = item.Tag as AwcStream;
|
|
var stereo = (audio?.ChannelStreams?.Length == 2);
|
|
if (stereo)
|
|
{
|
|
var name0 = audio.ChannelStreams[0].Name;
|
|
var left0 = name0.EndsWith("left") || name0.EndsWith(".l");
|
|
var f0 = left0 ? 1.0f : 0.0f;
|
|
var f1 = left0 ? 0.0f : 1.0f;
|
|
Player.LoadAudio(audio.ChannelStreams);
|
|
Player.SetVolume(VolumeTrackBar.Value / 100.0f);
|
|
Player.SetOutputMatrix(0, f0, f1);
|
|
Player.SetOutputMatrix(1, f1, f0);
|
|
Player.Play();
|
|
}
|
|
else if ((audio?.FormatChunk != null) || (audio?.StreamFormat != null))
|
|
{
|
|
Player.LoadAudio(audio);
|
|
Player.SetVolume(VolumeTrackBar.Value / 100.0f);
|
|
Player.Play();
|
|
}
|
|
else if (audio.MidiChunk != null)
|
|
{
|
|
//todo: play MIDI?
|
|
}
|
|
}
|
|
|
|
UpdateUI();
|
|
UpdatePlayerButtons();
|
|
}
|
|
|
|
private void PlayPrevious()
|
|
{
|
|
Stop();
|
|
if (PlayListView.SelectedIndices.Count > 0)
|
|
{
|
|
var nextIndex = PlayListView.SelectedIndices[0] - 1;
|
|
if (nextIndex >= 0)
|
|
{
|
|
PlayListView.Items[nextIndex].Selected = true;
|
|
PlayListView.Items[nextIndex].Focused = true;
|
|
Play();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void PlayNext()
|
|
{
|
|
Stop();
|
|
if (PlayListView.SelectedIndices.Count > 0)
|
|
{
|
|
var nextIndex = PlayListView.SelectedIndices[0] + 1;
|
|
if (nextIndex < PlayListView.Items.Count)
|
|
{
|
|
PlayListView.Items[nextIndex].Selected = true;
|
|
PlayListView.Items[nextIndex].Focused = true;
|
|
Play();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Pause()
|
|
{
|
|
Player.Pause();
|
|
UpdatePlayerButtons();
|
|
}
|
|
|
|
private void Resume()
|
|
{
|
|
Player.Resume();
|
|
UpdatePlayerButtons();
|
|
}
|
|
|
|
private void UpdateUI()
|
|
{
|
|
if ((Player.State != AudioPlayer.PlayerState.Stopped) && Player.trackFinished)
|
|
{
|
|
if (chbAutoJump.Checked)
|
|
PlayNext();
|
|
else
|
|
Stop();
|
|
}
|
|
|
|
if (Player.State != AudioPlayer.PlayerState.Stopped)
|
|
{
|
|
int playedMs = Player.PlayTimeMS;
|
|
int totalMs = Player.TotalTimeMS;
|
|
PositionTrackBar.Maximum = totalMs;
|
|
PositionTrackBar.Value = playedMs < totalMs ? playedMs : totalMs;
|
|
|
|
LabelTime.Text = TimeSpan.FromSeconds(playedMs / 1000).ToString("m\\:ss")
|
|
+ " / " + TimeSpan.FromSeconds(totalMs / 1000).ToString("m\\:ss");
|
|
}
|
|
else
|
|
{
|
|
PositionTrackBar.Value = 0;
|
|
}
|
|
}
|
|
|
|
private void UpdatePlayerButtons()
|
|
{
|
|
switch (Player.State)
|
|
{
|
|
case AudioPlayer.PlayerState.Playing:
|
|
PlayButton.Text = "\u275A\u275A";
|
|
StopButton.Enabled = true;
|
|
LabelTime.Visible = true;
|
|
break;
|
|
case AudioPlayer.PlayerState.Paused:
|
|
PlayButton.Text = "\u25B6";
|
|
StopButton.Enabled = true;
|
|
LabelTime.Visible = true;
|
|
break;
|
|
case AudioPlayer.PlayerState.Stopped:
|
|
PlayButton.Text = "\u25B6";
|
|
StopButton.Enabled = true;
|
|
LabelTime.Visible = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
private void PlayButton_Click(object sender, EventArgs e)
|
|
{
|
|
switch (Player.State)
|
|
{
|
|
case AudioPlayer.PlayerState.Stopped:
|
|
Play();
|
|
break;
|
|
case AudioPlayer.PlayerState.Playing:
|
|
Pause();
|
|
break;
|
|
case AudioPlayer.PlayerState.Paused:
|
|
Resume();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void StopButton_Click(object sender, EventArgs e)
|
|
{
|
|
Stop();
|
|
}
|
|
|
|
private void PrevButton_Click(object sender, EventArgs e)
|
|
{
|
|
PlayPrevious();
|
|
}
|
|
|
|
private void NextButton_Click(object sender, EventArgs e)
|
|
{
|
|
PlayNext();
|
|
}
|
|
|
|
private void PositionTrackBar_Scroll(object sender, EventArgs e)
|
|
{
|
|
PositionScrolled = true;
|
|
|
|
var t = PositionTrackBar.Value / 1000.0f;
|
|
|
|
Player.Seek(t);
|
|
}
|
|
|
|
private void PositionTrackBar_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
if (PositionScrolled)
|
|
{
|
|
PositionScrolled = false;
|
|
return;
|
|
}
|
|
PositionScrolled = false;
|
|
|
|
var f = Math.Min(Math.Max((e.X-13.0f) / (PositionTrackBar.Width-26.0f), 0.0f), 1.0f);
|
|
var v = f * (PositionTrackBar.Maximum / 1000.0f);
|
|
|
|
Player.Seek(v);
|
|
}
|
|
|
|
private void VolumeTrackBar_Scroll(object sender, EventArgs e)
|
|
{
|
|
Player.SetVolume((float)VolumeTrackBar.Value / 100);
|
|
}
|
|
|
|
private void Timer_Tick(object sender, EventArgs e)
|
|
{
|
|
UpdateUI();
|
|
}
|
|
|
|
private void PlayListView_DoubleClick(object sender, EventArgs e)
|
|
{
|
|
Play();
|
|
}
|
|
|
|
private void AwcForm_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
Stop();
|
|
Player.DisposeAudio();
|
|
}
|
|
|
|
private void ExportAsWav_Click(object sender, EventArgs e)
|
|
{
|
|
if (PlayListView.SelectedItems.Count == 1)
|
|
{
|
|
var item = PlayListView.SelectedItems[0];
|
|
var audio = item.Tag as AwcStream;
|
|
var stereo = (audio?.ChannelStreams?.Length == 2);
|
|
|
|
if (stereo)
|
|
{
|
|
MessageBox.Show("Sorry, export for stereo output is not currently available.");
|
|
return;
|
|
}
|
|
|
|
var ext = ".wav";
|
|
if (audio?.MidiChunk != null)
|
|
{
|
|
ext = ".midi";
|
|
}
|
|
|
|
saveFileDialog.FileName = audio.Name + ext;
|
|
if (saveFileDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
if (audio?.MidiChunk != null)
|
|
{
|
|
File.WriteAllBytes(saveFileDialog.FileName, audio.MidiChunk.Data);
|
|
}
|
|
else if ((audio?.FormatChunk != null) || (audio?.StreamFormat != null))
|
|
{
|
|
Stream wavStream = audio.GetWavStream();
|
|
FileStream stream = File.Create(saveFileDialog.FileName);
|
|
wavStream.CopyTo(stream);
|
|
stream.Close();
|
|
wavStream.Close();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
private void PlayListView_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
ExportAsWav.Text = "Export as .wav";
|
|
if (PlayListView.SelectedItems.Count == 1)
|
|
{
|
|
var item = PlayListView.SelectedItems[0];
|
|
var audio = item.Tag as AwcStream;
|
|
if (audio?.MidiChunk != null)
|
|
{
|
|
ExportAsWav.Text = "Export as .midi";
|
|
}
|
|
}
|
|
}
|
|
|
|
private void MainTabControl_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
if (MainTabControl.SelectedTab == XmlTabPage)
|
|
{
|
|
if (string.IsNullOrEmpty(XmlTextBox.Text))
|
|
{
|
|
LoadXml();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void XmlTextBox_VisibleRangeChangedDelayed(object sender, EventArgs e)
|
|
{
|
|
//this approach is much faster to load, but no outlining is available
|
|
|
|
//highlight only visible area of text
|
|
if (DelayHighlight)
|
|
{
|
|
HTMLSyntaxHighlight(XmlTextBox.VisibleRange);
|
|
}
|
|
}
|
|
|
|
private void XmlTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
|
{
|
|
if (!LoadingXml)
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|