diff --git a/Forms/AwcForm.Designer.cs b/Forms/AwcForm.Designer.cs
index cfee778..f78d5fa 100644
--- a/Forms/AwcForm.Designer.cs
+++ b/Forms/AwcForm.Designer.cs
@@ -28,12 +28,14 @@
///
private void InitializeComponent()
{
+ this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AwcForm));
this.MainTabControl = new System.Windows.Forms.TabControl();
this.PlayerTabPage = new System.Windows.Forms.TabPage();
+ this.VolumeLabel = new System.Windows.Forms.Label();
+ this.chbAutoJump = new System.Windows.Forms.CheckBox();
this.PrevButton = new System.Windows.Forms.Button();
this.NextButton = new System.Windows.Forms.Button();
- this.VolumeButton = new System.Windows.Forms.Button();
this.PlayButton = new System.Windows.Forms.Button();
this.PlayListView = new System.Windows.Forms.ListView();
this.PlaylistNameHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
@@ -43,7 +45,7 @@
this.PositionTrackBar = new System.Windows.Forms.TrackBar();
this.DetailsTabPage = new System.Windows.Forms.TabPage();
this.DetailsPropertyGrid = new CodeWalker.WinForms.PropertyGridFix();
- this.label1 = new System.Windows.Forms.Label();
+ this.Timer = new System.Windows.Forms.Timer(this.components);
this.MainTabControl.SuspendLayout();
this.PlayerTabPage.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.VolumeTrackBar)).BeginInit();
@@ -64,10 +66,10 @@
//
// PlayerTabPage
//
- this.PlayerTabPage.Controls.Add(this.label1);
+ this.PlayerTabPage.Controls.Add(this.VolumeLabel);
+ this.PlayerTabPage.Controls.Add(this.chbAutoJump);
this.PlayerTabPage.Controls.Add(this.PrevButton);
this.PlayerTabPage.Controls.Add(this.NextButton);
- this.PlayerTabPage.Controls.Add(this.VolumeButton);
this.PlayerTabPage.Controls.Add(this.PlayButton);
this.PlayerTabPage.Controls.Add(this.PlayListView);
this.PlayerTabPage.Controls.Add(this.VolumeTrackBar);
@@ -80,6 +82,26 @@
this.PlayerTabPage.Text = "Player";
this.PlayerTabPage.UseVisualStyleBackColor = true;
//
+ // VolumeLabel
+ //
+ this.VolumeLabel.AutoSize = true;
+ this.VolumeLabel.Location = new System.Drawing.Point(414, 305);
+ this.VolumeLabel.Name = "VolumeLabel";
+ this.VolumeLabel.Size = new System.Drawing.Size(42, 13);
+ this.VolumeLabel.TabIndex = 9;
+ this.VolumeLabel.Text = "Volume";
+ //
+ // chbAutoJump
+ //
+ this.chbAutoJump.AutoSize = true;
+ this.chbAutoJump.Enabled = false;
+ this.chbAutoJump.Location = new System.Drawing.Point(17, 305);
+ this.chbAutoJump.Name = "chbAutoJump";
+ this.chbAutoJump.Size = new System.Drawing.Size(108, 17);
+ this.chbAutoJump.TabIndex = 8;
+ this.chbAutoJump.Text = "Auto-jump to next";
+ this.chbAutoJump.UseVisualStyleBackColor = true;
+ //
// PrevButton
//
this.PrevButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
@@ -102,17 +124,6 @@
this.NextButton.UseVisualStyleBackColor = true;
this.NextButton.Click += new System.EventHandler(this.NextButton_Click);
//
- // VolumeButton
- //
- this.VolumeButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
- this.VolumeButton.Location = new System.Drawing.Point(426, 301);
- this.VolumeButton.Name = "VolumeButton";
- this.VolumeButton.Size = new System.Drawing.Size(33, 23);
- this.VolumeButton.TabIndex = 5;
- this.VolumeButton.Text = "Vol";
- this.VolumeButton.UseVisualStyleBackColor = true;
- this.VolumeButton.Click += new System.EventHandler(this.VolumeButton_Click);
- //
// PlayButton
//
this.PlayButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
@@ -136,11 +147,13 @@
this.PlayListView.FullRowSelect = true;
this.PlayListView.HideSelection = false;
this.PlayListView.Location = new System.Drawing.Point(6, 6);
+ this.PlayListView.MultiSelect = false;
this.PlayListView.Name = "PlayListView";
- this.PlayListView.Size = new System.Drawing.Size(556, 216);
+ this.PlayListView.Size = new System.Drawing.Size(556, 235);
this.PlayListView.TabIndex = 0;
this.PlayListView.UseCompatibleStateImageBehavior = false;
this.PlayListView.View = System.Windows.Forms.View.Details;
+ this.PlayListView.DoubleClick += new System.EventHandler(this.PlayListView_DoubleClick);
//
// PlaylistNameHeader
//
@@ -176,7 +189,7 @@
this.PositionTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.PositionTrackBar.BackColor = System.Drawing.SystemColors.ControlLightLight;
- this.PositionTrackBar.LargeChange = 50;
+ this.PositionTrackBar.LargeChange = 1000;
this.PositionTrackBar.Location = new System.Drawing.Point(6, 263);
this.PositionTrackBar.Maximum = 1000;
this.PositionTrackBar.Name = "PositionTrackBar";
@@ -205,14 +218,10 @@
this.DetailsPropertyGrid.Size = new System.Drawing.Size(562, 326);
this.DetailsPropertyGrid.TabIndex = 0;
//
- // label1
+ // Timer
//
- this.label1.AutoSize = true;
- this.label1.Location = new System.Drawing.Point(44, 238);
- this.label1.Name = "label1";
- this.label1.Size = new System.Drawing.Size(248, 13);
- this.label1.TabIndex = 7;
- this.label1.Text = "NOTE: Work in progress... Audio does not play yet!";
+ this.Timer.Enabled = true;
+ this.Timer.Tick += new System.EventHandler(this.Timer_Tick);
//
// AwcForm
//
@@ -223,6 +232,7 @@
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "AwcForm";
this.Text = "AWC Player - CodeWalker by dexyfex";
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.AwcForm_FormClosing);
this.MainTabControl.ResumeLayout(false);
this.PlayerTabPage.ResumeLayout(false);
this.PlayerTabPage.PerformLayout();
@@ -245,10 +255,11 @@
private System.Windows.Forms.ColumnHeader PlaylistLengthHeader;
private System.Windows.Forms.Button PrevButton;
private System.Windows.Forms.Button NextButton;
- private System.Windows.Forms.Button VolumeButton;
private System.Windows.Forms.Button PlayButton;
private System.Windows.Forms.TrackBar VolumeTrackBar;
private System.Windows.Forms.TrackBar PositionTrackBar;
- private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Timer Timer;
+ private System.Windows.Forms.CheckBox chbAutoJump;
+ private System.Windows.Forms.Label VolumeLabel;
}
}
\ No newline at end of file
diff --git a/Forms/AwcForm.cs b/Forms/AwcForm.cs
index 3b754bf..6f144f5 100644
--- a/Forms/AwcForm.cs
+++ b/Forms/AwcForm.cs
@@ -2,15 +2,8 @@
using SharpDX.Multimedia;
using SharpDX.XAudio2;
using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Drawing;
using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
+using System.Diagnostics;
using System.Windows.Forms;
namespace CodeWalker.Forms
@@ -19,6 +12,11 @@ namespace CodeWalker.Forms
{
public AwcFile Awc { get; set; }
+ private XAudio2 xAudio2;
+ private MasteringVoice masteringVoice;
+ private AudioBuffer audioBuffer;
+ private SourceVoice sourceVoice;
+
private string fileName;
public string FileName
{
@@ -31,36 +29,35 @@ namespace CodeWalker.Forms
}
public string FilePath { get; set; }
- private bool Playing = false;
+ private enum PlayerState { Stopped, Playing, Paused };
+ private PlayerState playerState = PlayerState.Stopped;
+ private Stopwatch playtime;
+ private float trackLength;
public AwcForm()
{
InitializeComponent();
+
+ playtime = new Stopwatch();
}
-
-
private void UpdateFormTitle()
{
Text = fileName + " - AWC Player - CodeWalker by dexyfex";
}
-
public void LoadAwc(AwcFile awc)
{
Awc = awc;
DetailsPropertyGrid.SelectedObject = awc;
- //MainTabControl.SelectedTab = DetailsTabPage;//remove this
-
fileName = awc?.Name;
if (string.IsNullOrEmpty(fileName))
{
fileName = awc?.FileEntry?.Name;
}
-
PlayListView.Items.Clear();
if (awc.Audios != null)
{
@@ -76,79 +73,129 @@ namespace CodeWalker.Forms
UpdateFormTitle();
}
+ private void Stop()
+ {
+ if (playerState != PlayerState.Stopped)
+ {
+ sourceVoice.DestroyVoice();
+ sourceVoice.Dispose();
+ audioBuffer.Stream.Dispose();
+ SetPlayerState(PlayerState.Stopped);
+ }
+ }
+
+ private void SetPlayerState(PlayerState newState)
+ {
+ if (playerState != newState)
+ {
+ switch (newState)
+ {
+ case PlayerState.Playing:
+ if (playerState == PlayerState.Stopped)
+ playtime.Reset();
+ playtime.Start();
+ break;
+ default:
+ playtime.Stop();
+ break;
+ }
+
+ playerState = newState;
+ }
+ }
+
+ private void InitializeAudio(AwcAudio audio)
+ {
+ trackLength = audio.Length;
+
+ if (xAudio2 == null)
+ {
+ xAudio2 = new XAudio2();
+ masteringVoice = new MasteringVoice(xAudio2);
+ }
+
+ Stream wavStream = audio.GetWavStream();
+ SoundStream soundStream = new SoundStream(wavStream);
+ audioBuffer = new AudioBuffer
+ {
+ Stream = soundStream.ToDataStream(),
+ AudioBytes = (int)soundStream.Length,
+ Flags = BufferFlags.EndOfStream
+ };
+ soundStream.Close();
+ wavStream.Close();
+
+ sourceVoice = new SourceVoice(xAudio2, soundStream.Format, true);
+ sourceVoice.SubmitSourceBuffer(audioBuffer, soundStream.DecodedPacketsInfo);
+ sourceVoice.SetVolume((float)VolumeTrackBar.Value / 100);
+ }
private void Play()
{
- if (PlayListView.SelectedItems.Count != 1) return;
+ Stop();
- var item = PlayListView.SelectedItems[0];
- var audio = item.Tag as AwcAudio;
+ if (PlayListView.SelectedItems.Count == 1)
+ {
+ var item = PlayListView.SelectedItems[0];
+ var audio = item.Tag as AwcAudio;
- if (audio == null) return;
-
-
-
- //see https://github.com/sharpdx/SharpDX-Samples/blob/master/Desktop/XAudio2/PlaySound/Program.cs
- //see https://github.com/sharpdx/SharpDX-Samples/blob/master/Desktop/XAudio2/AudioPlayerApp/AudioPlayer.cs
-
- //var mstrm = new MemoryStream(audio.Data);
- //var sstrm = new SoundStream(mstrm);
- //SourceVoice sv=new SourceVoice()
- var mstrm = audio.GetWavStream();
-
- ////var mdata = ((MemoryStream)mstrm).GetBuffer();
- ////File.WriteAllBytes("C:\\test2.wav", mdata);
- ////return;
-
- //var sstrm = new SoundStream(mstrm);
- //var waveFormat = sstrm.Format;
- //var buffer = new AudioBuffer
- //{
- // Stream = sstrm.ToDataStream(),
- // AudioBytes = (int)sstrm.Length,
- // Flags = BufferFlags.EndOfStream
- //};
- //sstrm.Close();
-
-
- //var xaudio2 = new XAudio2();//cache this...
- //var masteringVoice = new MasteringVoice(xaudio2);//cache this...
- //var sourceVoice = new SourceVoice(xaudio2, waveFormat, true);
- ////sourceVoice.BufferEnd += (context) => Console.WriteLine(" => event received: end of buffer");
- //sourceVoice.SubmitSourceBuffer(buffer, sstrm.DecodedPacketsInfo);
- //sourceVoice.Start();
- //while (sourceVoice.State.BuffersQueued > 0) // && !IsKeyPressed(ConsoleKey.Escape))
- //{
- // Thread.Sleep(10);
- //}
- //sourceVoice.DestroyVoice();
- //sourceVoice.Dispose();
- //buffer.Stream.Dispose();
-
- //masteringVoice.Dispose();//on form exit?
- //xaudio2.Dispose();//on form exit?
-
-
-
- Playing = true;
+ if (audio != null)
+ {
+ InitializeAudio(audio);
+ sourceVoice.Start();
+ SetPlayerState(PlayerState.Playing);
+ }
+ }
}
+ 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()
{
-
- Playing = false;
+ if (playerState == PlayerState.Playing)
+ {
+ sourceVoice.Stop();
+ SetPlayerState(PlayerState.Paused);
+ }
}
- private void Prev()
- {
+ private void Resume()
+ {
+ if (playerState == PlayerState.Paused)
+ {
+ sourceVoice.Start();
+ SetPlayerState(PlayerState.Playing);
+ }
}
- private void Next()
- {
- }
-
-
-
private void PositionTrackBar_Scroll(object sender, EventArgs e)
{
@@ -156,41 +203,66 @@ namespace CodeWalker.Forms
private void PlayButton_Click(object sender, EventArgs e)
{
- if (Playing) Pause();
- else Play();
+ switch (playerState)
+ {
+ case PlayerState.Stopped:
+ Play();
+ break;
+ case PlayerState.Playing:
+ Pause();
+ break;
+ case PlayerState.Paused:
+ Resume();
+ break;
+ }
}
private void PrevButton_Click(object sender, EventArgs e)
{
- Prev();
+ PlayPrevious();
}
private void NextButton_Click(object sender, EventArgs e)
{
- Next();
- }
-
- private void VolumeButton_Click(object sender, EventArgs e)
- {
-
+ PlayNext();
}
private void VolumeTrackBar_Scroll(object sender, EventArgs e)
{
-
- }
+ if (playerState == PlayerState.Playing)
+ sourceVoice.SetVolume((float)VolumeTrackBar.Value / 100);
+ }
+
+ private void Timer_Tick(object sender, EventArgs e)
+ {
+ if (playerState != PlayerState.Stopped)
+ {
+ int playedMs = (int)playtime.Elapsed.TotalMilliseconds;
+ int totalMs = (int)(trackLength * 1000);
+ PositionTrackBar.Maximum = totalMs;
+ PositionTrackBar.Value = playedMs < totalMs ? playedMs : totalMs;
+ }
+ else
+ {
+ PositionTrackBar.Value = 0;
+ }
+ }
+
+ private void PlayListView_DoubleClick(object sender, EventArgs e)
+ {
+ if (playerState == PlayerState.Playing)
+ Stop();
+ Play();
+ }
+
+ private void AwcForm_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ Stop();
+ if (xAudio2 != null)
+ {
+ masteringVoice.Dispose();
+ xAudio2.Dispose();
+ }
+ }
}
-
-
-
-
-
-
- public class AudioPlayer
- {
-
- }
-
-
-
}
diff --git a/Forms/AwcForm.resx b/Forms/AwcForm.resx
index 1431f6b..3badf1f 100644
--- a/Forms/AwcForm.resx
+++ b/Forms/AwcForm.resx
@@ -117,6 +117,9 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ 17, 17
+
diff --git a/GameFiles/FileTypes/AwcFile.cs b/GameFiles/FileTypes/AwcFile.cs
index c39649b..aeb64d6 100644
--- a/GameFiles/FileTypes/AwcFile.cs
+++ b/GameFiles/FileTypes/AwcFile.cs
@@ -414,9 +414,9 @@ namespace CodeWalker.GameFiles
[TC(typeof(EXP))] public class AwcFormatChunk
{
public uint Samples { get; set; }
- public int UnkMinusOne { get; set; }
+ public int LoopPoint { get; set; }
public ushort SamplesPerSecond { get; set; }
- public ushort Unk1 { get; set; }
+ public short Headroom { get; set; }
public ushort Unk2 { get; set; }
public ushort Unk3 { get; set; }
public ushort Unk4 { get; set; }
@@ -426,9 +426,9 @@ namespace CodeWalker.GameFiles
public AwcFormatChunk(DataReader r)
{
Samples = r.ReadUInt32();
- UnkMinusOne = r.ReadInt32();
+ LoopPoint = r.ReadInt32();
SamplesPerSecond = r.ReadUInt16();
- Unk1 = r.ReadUInt16();
+ Headroom = r.ReadInt16();
Unk2 = r.ReadUInt16();
Unk3 = r.ReadUInt16();
Unk4 = r.ReadUInt16();
@@ -443,7 +443,7 @@ namespace CodeWalker.GameFiles
public override string ToString()
{
- return Unk1.ToString() + ", " + Unk6.ToString() + ": " + Samples.ToString() + " samples, " + SamplesPerSecond.ToString() + " samples/sec";
+ return Headroom.ToString() + ", " + Unk6.ToString() + ": " + Samples.ToString() + " samples, " + SamplesPerSecond.ToString() + " samples/sec";
}
}
@@ -503,14 +503,20 @@ namespace CodeWalker.GameFiles
return fmt + ((hz > 0) ? (", " + hz.ToString() + " Hz") : "");
}
}
+
+ public float Length
+ {
+ get
+ {
+ return Format == null ? 0 : (float)Format.Samples / Format.SamplesPerSecond;
+ }
+ }
+
public string LengthStr
{
get
{
- if (Format == null) return "0:00";
- float sec = (float)Format.Samples / Format.SamplesPerSecond;
- TimeSpan ts = TimeSpan.FromSeconds(sec);
- return ts.ToString("m\\:ss");
+ return TimeSpan.FromSeconds(Length).ToString("m\\:ss");
}
}
@@ -534,8 +540,8 @@ namespace CodeWalker.GameFiles
public Stream GetWavStream()
{
- MemoryStream ms = new MemoryStream();
- BinaryWriter w = new BinaryWriter(ms);
+ MemoryStream stream = new MemoryStream();
+ BinaryWriter w = new BinaryWriter(stream);
//see http://icculus.org/SDL_sound/downloads/external_documentation/wavecomp.htm
@@ -543,70 +549,38 @@ namespace CodeWalker.GameFiles
//see https://msdn.microsoft.com/en-us/library/windows/desktop/ff538799(v=vs.85).aspx
- int sampleCount = SampleCount;
int samplesPerSec = SamplesPerSecond;
- //short sampleSize = (short)((BitsPerSample / 8) * Channels);//2
- //int avgBytesPerSec = sampleSize * samplesPerSec;
- short blockAlign = 512;
- short samplesPerBlock = (short)((((blockAlign - (7 * Channels)) * 8) / (BitsPerSample * Channels)) + 2);
- int avgBytesPerSec = ((samplesPerSec / samplesPerBlock) * blockAlign);
-
- w.Write("RIFF".ToCharArray());
- w.Write(0); //file size written later...
- w.Write("WAVE".ToCharArray());
- w.Write("fmt ".ToCharArray());
- w.Write(50); //(PCM:16) //header size
- w.Write((short)2); //pcm format tag 1=PCM, 2=ADPCM
- w.Write(Channels);
- w.Write(samplesPerSec);
- w.Write(avgBytesPerSec);
- w.Write(blockAlign);// sampleSize);
- w.Write(BitsPerSample);
- w.Write((short)32);//extra byte count for WAVEFORMATEX
-
- w.Write(samplesPerBlock);
- w.Write((short)7);//num coefficients
- w.Write((short)256); //coeff 0
- w.Write((short)0);
- w.Write((short)512); //coeff 1
- w.Write((short)-256);
- w.Write((short)0); //coeff 2
- w.Write((short)0);
- w.Write((short)192); //coeff 3
- w.Write((short)64);
- w.Write((short)240); //coeff 4
- w.Write((short)0);
- w.Write((short)460); //coeff 5
- w.Write((short)-208);
- w.Write((short)392); //coeff 6
- w.Write((short)-232);
+ Channels = 1;
+ BitsPerSample = 16;
+ int byteRate = samplesPerSec * Channels * BitsPerSample / 8;
+ short blockAlign = (short)(Channels * BitsPerSample / 8);
+
+ // RIFF chunk
+ var fileSize = 4 + 24 + 8 + Data.Length;
+ w.Write("RIFF".ToCharArray()); // 0x00 - "RIFF" magic
+ w.Write(fileSize); // 0x04 - file size
+ w.Write("WAVE".ToCharArray()); // 0x08 - "WAVE" magic
+ // fmt sub-chunk
+ w.Write("fmt ".ToCharArray()); // 0x0C - "fmt " magic
+ w.Write(16); // 0x10 - header size (16 bytes)
+ w.Write((short)1); // 0x14 - audio format (1=PCM)
+ w.Write(Channels); // 0x16 - number of channels
+ w.Write(samplesPerSec); // 0x18
+ w.Write(byteRate); // 0x1C
+ w.Write(blockAlign);// sampleSize); // 0x20
+ w.Write(BitsPerSample); // 0x22
+
+ // data sub-chunk
w.Write("data".ToCharArray());
- w.Write(0); //data size written later...
-
- if (sampleCount != 0)
- {
-
- //var sc = sampleCount * sampleSize;
- var datalen = Data.Length;
- w.Write(Data);
- }
- else
- {
- w.Write(Data);
- }
-
- ms.Position = 4;
- w.Write((int)ms.Length - 8);
-
- ms.Position = 74;// 40;
- w.Write((int)ms.Length - 78);// 44);
+ w.Write(Data.Length);
+ w.Write(Data);
w.Flush();
- ms.Position = 0;
- return ms;
+ stream.Position = 0;
+ return stream;
}