diff --git a/Forms/AwcForm.Designer.cs b/Forms/AwcForm.Designer.cs
index f78d5fa..62f26a6 100644
--- a/Forms/AwcForm.Designer.cs
+++ b/Forms/AwcForm.Designer.cs
@@ -32,6 +32,9 @@
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.LabelInfo = new System.Windows.Forms.Label();
+ this.LabelTime = new System.Windows.Forms.Label();
+ this.StopButton = new System.Windows.Forms.Button();
this.VolumeLabel = new System.Windows.Forms.Label();
this.chbAutoJump = new System.Windows.Forms.CheckBox();
this.PrevButton = new System.Windows.Forms.Button();
@@ -41,13 +44,18 @@
this.PlaylistNameHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.PlaylistTypeHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.PlaylistLengthHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.ExportAsWav = new System.Windows.Forms.ToolStripMenuItem();
this.VolumeTrackBar = new System.Windows.Forms.TrackBar();
this.PositionTrackBar = new System.Windows.Forms.TrackBar();
this.DetailsTabPage = new System.Windows.Forms.TabPage();
this.DetailsPropertyGrid = new CodeWalker.WinForms.PropertyGridFix();
this.Timer = new System.Windows.Forms.Timer(this.components);
+ this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
+ this.PlaylistSizeHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.MainTabControl.SuspendLayout();
this.PlayerTabPage.SuspendLayout();
+ this.contextMenuStrip.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.VolumeTrackBar)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.PositionTrackBar)).BeginInit();
this.DetailsTabPage.SuspendLayout();
@@ -61,11 +69,14 @@
this.MainTabControl.Location = new System.Drawing.Point(0, 0);
this.MainTabControl.Name = "MainTabControl";
this.MainTabControl.SelectedIndex = 0;
- this.MainTabControl.Size = new System.Drawing.Size(576, 358);
+ this.MainTabControl.Size = new System.Drawing.Size(576, 361);
this.MainTabControl.TabIndex = 0;
//
// PlayerTabPage
//
+ this.PlayerTabPage.Controls.Add(this.LabelInfo);
+ this.PlayerTabPage.Controls.Add(this.LabelTime);
+ this.PlayerTabPage.Controls.Add(this.StopButton);
this.PlayerTabPage.Controls.Add(this.VolumeLabel);
this.PlayerTabPage.Controls.Add(this.chbAutoJump);
this.PlayerTabPage.Controls.Add(this.PrevButton);
@@ -77,25 +88,54 @@
this.PlayerTabPage.Location = new System.Drawing.Point(4, 22);
this.PlayerTabPage.Name = "PlayerTabPage";
this.PlayerTabPage.Padding = new System.Windows.Forms.Padding(3);
- this.PlayerTabPage.Size = new System.Drawing.Size(568, 332);
+ this.PlayerTabPage.Size = new System.Drawing.Size(568, 335);
this.PlayerTabPage.TabIndex = 0;
this.PlayerTabPage.Text = "Player";
this.PlayerTabPage.UseVisualStyleBackColor = true;
//
+ // LabelInfo
+ //
+ this.LabelInfo.AutoSize = true;
+ this.LabelInfo.Location = new System.Drawing.Point(8, 247);
+ this.LabelInfo.Name = "LabelInfo";
+ this.LabelInfo.Size = new System.Drawing.Size(0, 13);
+ this.LabelInfo.TabIndex = 12;
+ //
+ // LabelTime
+ //
+ this.LabelTime.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.LabelTime.Location = new System.Drawing.Point(285, 308);
+ this.LabelTime.Name = "LabelTime";
+ this.LabelTime.Size = new System.Drawing.Size(114, 17);
+ this.LabelTime.TabIndex = 11;
+ this.LabelTime.TextAlign = System.Drawing.ContentAlignment.TopCenter;
+ //
+ // StopButton
+ //
+ this.StopButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.StopButton.Enabled = false;
+ this.StopButton.Location = new System.Drawing.Point(211, 304);
+ this.StopButton.Name = "StopButton";
+ this.StopButton.Size = new System.Drawing.Size(31, 23);
+ this.StopButton.TabIndex = 10;
+ this.StopButton.Text = "◼";
+ this.StopButton.UseVisualStyleBackColor = true;
+ //
// VolumeLabel
//
+ this.VolumeLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.VolumeLabel.AutoSize = true;
- this.VolumeLabel.Location = new System.Drawing.Point(414, 305);
+ this.VolumeLabel.Location = new System.Drawing.Point(405, 308);
this.VolumeLabel.Name = "VolumeLabel";
- this.VolumeLabel.Size = new System.Drawing.Size(42, 13);
+ this.VolumeLabel.Size = new System.Drawing.Size(60, 13);
this.VolumeLabel.TabIndex = 9;
- this.VolumeLabel.Text = "Volume";
+ this.VolumeLabel.Text = "🕩 Volume";
//
// chbAutoJump
//
+ this.chbAutoJump.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.chbAutoJump.AutoSize = true;
- this.chbAutoJump.Enabled = false;
- this.chbAutoJump.Location = new System.Drawing.Point(17, 305);
+ this.chbAutoJump.Location = new System.Drawing.Point(17, 308);
this.chbAutoJump.Name = "chbAutoJump";
this.chbAutoJump.Size = new System.Drawing.Size(108, 17);
this.chbAutoJump.TabIndex = 8;
@@ -104,34 +144,34 @@
//
// PrevButton
//
- this.PrevButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
- this.PrevButton.Location = new System.Drawing.Point(137, 301);
+ this.PrevButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.PrevButton.Location = new System.Drawing.Point(137, 304);
this.PrevButton.Name = "PrevButton";
this.PrevButton.Size = new System.Drawing.Size(31, 23);
this.PrevButton.TabIndex = 2;
- this.PrevButton.Text = "<<";
+ this.PrevButton.Text = "⏮";
this.PrevButton.UseVisualStyleBackColor = true;
this.PrevButton.Click += new System.EventHandler(this.PrevButton_Click);
//
// NextButton
//
- this.NextButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
- this.NextButton.Location = new System.Drawing.Point(255, 301);
+ this.NextButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.NextButton.Location = new System.Drawing.Point(248, 304);
this.NextButton.Name = "NextButton";
this.NextButton.Size = new System.Drawing.Size(31, 23);
this.NextButton.TabIndex = 4;
- this.NextButton.Text = ">>";
+ this.NextButton.Text = "⏭";
this.NextButton.UseVisualStyleBackColor = true;
this.NextButton.Click += new System.EventHandler(this.NextButton_Click);
//
// PlayButton
//
- this.PlayButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
- this.PlayButton.Location = new System.Drawing.Point(174, 301);
+ this.PlayButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.PlayButton.Location = new System.Drawing.Point(174, 304);
this.PlayButton.Name = "PlayButton";
- this.PlayButton.Size = new System.Drawing.Size(75, 23);
+ this.PlayButton.Size = new System.Drawing.Size(31, 23);
this.PlayButton.TabIndex = 3;
- this.PlayButton.Text = "Play/Pause";
+ this.PlayButton.Text = "▶";
this.PlayButton.UseVisualStyleBackColor = true;
this.PlayButton.Click += new System.EventHandler(this.PlayButton_Click);
//
@@ -143,13 +183,15 @@
this.PlayListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.PlaylistNameHeader,
this.PlaylistTypeHeader,
- this.PlaylistLengthHeader});
+ this.PlaylistLengthHeader,
+ this.PlaylistSizeHeader});
+ this.PlayListView.ContextMenuStrip = this.contextMenuStrip;
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, 235);
+ this.PlayListView.Size = new System.Drawing.Size(556, 238);
this.PlayListView.TabIndex = 0;
this.PlayListView.UseCompatibleStateImageBehavior = false;
this.PlayListView.View = System.Windows.Forms.View.Details;
@@ -158,7 +200,7 @@
// PlaylistNameHeader
//
this.PlaylistNameHeader.Text = "Name";
- this.PlaylistNameHeader.Width = 303;
+ this.PlaylistNameHeader.Width = 260;
//
// PlaylistTypeHeader
//
@@ -168,14 +210,29 @@
// PlaylistLengthHeader
//
this.PlaylistLengthHeader.Text = "Length";
- this.PlaylistLengthHeader.Width = 110;
+ this.PlaylistLengthHeader.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+ this.PlaylistLengthHeader.Width = 80;
+ //
+ // contextMenuStrip
+ //
+ this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.ExportAsWav});
+ this.contextMenuStrip.Name = "contextMenuStrip1";
+ this.contextMenuStrip.Size = new System.Drawing.Size(153, 48);
+ //
+ // ExportAsWav
+ //
+ this.ExportAsWav.Name = "ExportAsWav";
+ this.ExportAsWav.Size = new System.Drawing.Size(152, 22);
+ this.ExportAsWav.Text = "Export as .wav";
+ this.ExportAsWav.Click += new System.EventHandler(this.ExportAsWav_Click);
//
// VolumeTrackBar
//
this.VolumeTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.VolumeTrackBar.BackColor = System.Drawing.SystemColors.ControlLightLight;
this.VolumeTrackBar.LargeChange = 10;
- this.VolumeTrackBar.Location = new System.Drawing.Point(455, 301);
+ this.VolumeTrackBar.Location = new System.Drawing.Point(455, 304);
this.VolumeTrackBar.Maximum = 100;
this.VolumeTrackBar.Name = "VolumeTrackBar";
this.VolumeTrackBar.Size = new System.Drawing.Size(105, 45);
@@ -190,7 +247,7 @@
| System.Windows.Forms.AnchorStyles.Right)));
this.PositionTrackBar.BackColor = System.Drawing.SystemColors.ControlLightLight;
this.PositionTrackBar.LargeChange = 1000;
- this.PositionTrackBar.Location = new System.Drawing.Point(6, 263);
+ this.PositionTrackBar.Location = new System.Drawing.Point(6, 266);
this.PositionTrackBar.Maximum = 1000;
this.PositionTrackBar.Name = "PositionTrackBar";
this.PositionTrackBar.Size = new System.Drawing.Size(554, 45);
@@ -204,7 +261,7 @@
this.DetailsTabPage.Location = new System.Drawing.Point(4, 22);
this.DetailsTabPage.Name = "DetailsTabPage";
this.DetailsTabPage.Padding = new System.Windows.Forms.Padding(3);
- this.DetailsTabPage.Size = new System.Drawing.Size(568, 332);
+ this.DetailsTabPage.Size = new System.Drawing.Size(568, 335);
this.DetailsTabPage.TabIndex = 1;
this.DetailsTabPage.Text = "Details";
this.DetailsTabPage.UseVisualStyleBackColor = true;
@@ -215,27 +272,41 @@
this.DetailsPropertyGrid.HelpVisible = false;
this.DetailsPropertyGrid.Location = new System.Drawing.Point(3, 3);
this.DetailsPropertyGrid.Name = "DetailsPropertyGrid";
- this.DetailsPropertyGrid.Size = new System.Drawing.Size(562, 326);
+ this.DetailsPropertyGrid.Size = new System.Drawing.Size(562, 329);
this.DetailsPropertyGrid.TabIndex = 0;
//
// Timer
//
this.Timer.Enabled = true;
+ this.Timer.Interval = 25;
this.Timer.Tick += new System.EventHandler(this.Timer_Tick);
//
+ // saveFileDialog
+ //
+ this.saveFileDialog.DefaultExt = "wav";
+ this.saveFileDialog.Filter = "Wave files (*.wav)|*.wav";
+ //
+ // PlaylistSizeHeader
+ //
+ this.PlaylistSizeHeader.Text = "Size";
+ this.PlaylistSizeHeader.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+ this.PlaylistSizeHeader.Width = 80;
+ //
// AwcForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(576, 358);
+ this.ClientSize = new System.Drawing.Size(576, 361);
this.Controls.Add(this.MainTabControl);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MinimumSize = new System.Drawing.Size(592, 300);
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();
+ this.contextMenuStrip.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.VolumeTrackBar)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.PositionTrackBar)).EndInit();
this.DetailsTabPage.ResumeLayout(false);
@@ -261,5 +332,12 @@
private System.Windows.Forms.Timer Timer;
private System.Windows.Forms.CheckBox chbAutoJump;
private System.Windows.Forms.Label VolumeLabel;
+ private System.Windows.Forms.Button StopButton;
+ private System.Windows.Forms.Label LabelTime;
+ private System.Windows.Forms.Label LabelInfo;
+ private System.Windows.Forms.ContextMenuStrip contextMenuStrip;
+ private System.Windows.Forms.ToolStripMenuItem ExportAsWav;
+ private System.Windows.Forms.SaveFileDialog saveFileDialog;
+ private System.Windows.Forms.ColumnHeader PlaylistSizeHeader;
}
}
\ No newline at end of file
diff --git a/Forms/AwcForm.cs b/Forms/AwcForm.cs
index 6f144f5..9cd1282 100644
--- a/Forms/AwcForm.cs
+++ b/Forms/AwcForm.cs
@@ -1,78 +1,86 @@
-using CodeWalker.GameFiles;
-using SharpDX.Multimedia;
-using SharpDX.XAudio2;
-using System;
-using System.IO;
-using System.Diagnostics;
-using System.Windows.Forms;
-
-namespace CodeWalker.Forms
-{
- public partial class AwcForm : Form
- {
- public AwcFile Awc { get; set; }
-
+using CodeWalker.GameFiles;
+using SharpDX.Multimedia;
+using SharpDX.XAudio2;
+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Windows.Forms;
+
+namespace CodeWalker.Forms
+{
+ public partial class AwcForm : Form
+ {
+ public AwcFile Awc { get; set; }
+
+ private AwcAudio currentAudio;
private XAudio2 xAudio2;
private MasteringVoice masteringVoice;
private AudioBuffer audioBuffer;
- private SourceVoice sourceVoice;
+ private SourceVoice sourceVoice;
+
+ private string fileName;
+ public string FileName
+ {
+ get { return fileName; }
+ set
+ {
+ fileName = value;
+ UpdateFormTitle();
+ }
+ }
+ public string FilePath { get; set; }
+
+ private enum PlayerState { Stopped, Playing, Paused };
+ private PlayerState playerState = PlayerState.Stopped;
+
+ private Stopwatch playtime;
+ private int playBeginMs;
+ private float trackLength;
+ private bool trackFinished;
+
+ 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;
+
+ fileName = awc?.Name;
+ if (string.IsNullOrEmpty(fileName))
+ {
+ fileName = awc?.FileEntry?.Name;
+ }
+
+ PlayListView.Items.Clear();
+
+ float totalLength = 0;
+ if (awc.Audios != null)
+ {
+ foreach (var audio in awc.Audios)
+ {
+ var item = PlayListView.Items.Add(audio.Name);
+ item.SubItems.Add(audio.Type);
+ item.SubItems.Add(audio.LengthStr);
+ item.SubItems.Add(TextUtil.GetBytesReadable(audio.Data.Length));
+ item.Tag = audio;
+ totalLength += audio.Length;
+ }
+ }
+
+ LabelInfo.Text = awc.Audios.Length.ToString() + " track(s), Length: " + TimeSpan.FromSeconds((float)totalLength).ToString("m\\:ss");
+ UpdateFormTitle();
+ }
- private string fileName;
- public string FileName
- {
- get { return fileName; }
- set
- {
- fileName = value;
- UpdateFormTitle();
- }
- }
- public string FilePath { get; set; }
-
- 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;
-
- fileName = awc?.Name;
- if (string.IsNullOrEmpty(fileName))
- {
- fileName = awc?.FileEntry?.Name;
- }
-
- PlayListView.Items.Clear();
- if (awc.Audios != null)
- {
- foreach (var audio in awc.Audios)
- {
- var item = PlayListView.Items.Add(audio.Name);
- item.SubItems.Add(audio.Type);
- item.SubItems.Add(audio.LengthStr);
- item.Tag = audio;
- }
- }
-
- UpdateFormTitle();
- }
-
private void Stop()
{
if (playerState != PlayerState.Stopped)
@@ -82,8 +90,8 @@ namespace CodeWalker.Forms
audioBuffer.Stream.Dispose();
SetPlayerState(PlayerState.Stopped);
}
- }
-
+ }
+
private void SetPlayerState(PlayerState newState)
{
if (playerState != newState)
@@ -94,60 +102,88 @@ namespace CodeWalker.Forms
if (playerState == PlayerState.Stopped)
playtime.Reset();
playtime.Start();
+
+ PlayButton.Text = "\u275A\u275A";
+ StopButton.Enabled = true;
+ LabelTime.Visible = true;
break;
- default:
+ case PlayerState.Paused:
playtime.Stop();
+ PlayButton.Text = "\u25B6";
+ StopButton.Enabled = true;
+ LabelTime.Visible = true;
+ break;
+ case PlayerState.Stopped:
+ playtime.Stop();
+ PlayButton.Text = "\u25B6";
+ LabelTime.Visible = false;
+ StopButton.Enabled = true;
break;
}
playerState = newState;
+ UpdateUI();
}
- }
-
- private void InitializeAudio(AwcAudio audio)
+ }
+
+ private void InitializeAudio(AwcAudio audio, float playBegin = 0)
{
+ currentAudio = audio;
trackLength = audio.Length;
if (xAudio2 == null)
- {
- xAudio2 = new XAudio2();
- masteringVoice = new MasteringVoice(xAudio2);
+ {
+ 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 soundStream = new SoundStream(wavStream);
+ audioBuffer = new AudioBuffer
+ {
+ Stream = soundStream.ToDataStream(),
+ AudioBytes = (int)soundStream.Length,
+ Flags = BufferFlags.EndOfStream
};
+ if (playBegin > 0)
+ {
+ audioBuffer.PlayBegin = (int)(soundStream.Format.SampleRate * playBegin) / 128 * 128;
+ if (playtime.IsRunning)
+ playtime.Restart();
+ else
+ playtime.Reset();
+ playBeginMs = (int)(playBegin * 1000);
+ }
+ else
+ playBeginMs = 0;
soundStream.Close();
wavStream.Close();
- sourceVoice = new SourceVoice(xAudio2, soundStream.Format, true);
+ trackFinished = false;
+ sourceVoice = new SourceVoice(xAudio2, soundStream.Format, true);
sourceVoice.SubmitSourceBuffer(audioBuffer, soundStream.DecodedPacketsInfo);
- sourceVoice.SetVolume((float)VolumeTrackBar.Value / 100);
- }
-
- private void Play()
- {
- Stop();
-
+ sourceVoice.BufferEnd += (context) => trackFinished = true;
+ sourceVoice.SetVolume((float)VolumeTrackBar.Value / 100);
+ }
+
+ private void Play()
+ {
+ Stop();
+
if (PlayListView.SelectedItems.Count == 1)
- {
- var item = PlayListView.SelectedItems[0];
- var audio = item.Tag as AwcAudio;
-
+ {
+ var item = PlayListView.SelectedItems[0];
+ var audio = item.Tag as AwcAudio;
+
if (audio != null)
{
- InitializeAudio(audio);
+ InitializeAudio(audio);
sourceVoice.Start();
SetPlayerState(PlayerState.Playing);
}
}
- }
-
+ }
+
private void PlayPrevious()
{
Stop();
@@ -161,8 +197,8 @@ namespace CodeWalker.Forms
Play();
}
}
- }
-
+ }
+
private void PlayNext()
{
Stop();
@@ -176,33 +212,36 @@ namespace CodeWalker.Forms
Play();
}
}
- }
+ }
- private void Pause()
- {
+ private void Pause()
+ {
if (playerState == PlayerState.Playing)
{
- sourceVoice.Stop();
- SetPlayerState(PlayerState.Paused);
- }
- }
-
+ sourceVoice.Stop();
+ SetPlayerState(PlayerState.Paused);
+ }
+ }
+
private void Resume()
{
if (playerState == PlayerState.Paused)
{
- sourceVoice.Start();
- SetPlayerState(PlayerState.Playing);
+ sourceVoice.Start();
+ SetPlayerState(PlayerState.Playing);
}
- }
-
- private void PositionTrackBar_Scroll(object sender, EventArgs e)
- {
-
- }
-
- private void PlayButton_Click(object sender, EventArgs e)
- {
+ }
+
+ private void PositionTrackBar_Scroll(object sender, EventArgs e)
+ {
+
+ sourceVoice.Stop();
+ InitializeAudio(currentAudio, PositionTrackBar.Value / 1000);
+ sourceVoice.Start();
+ }
+
+ private void PlayButton_Click(object sender, EventArgs e)
+ {
switch (playerState)
{
case PlayerState.Stopped:
@@ -214,33 +253,44 @@ namespace CodeWalker.Forms
case PlayerState.Paused:
Resume();
break;
- }
- }
-
- private void PrevButton_Click(object sender, EventArgs e)
- {
- PlayPrevious();
- }
-
- private void NextButton_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)
+ private void PrevButton_Click(object sender, EventArgs e)
{
+ PlayPrevious();
+ }
+
+ private void NextButton_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 UpdateUI()
+ {
+ if (playerState != PlayerState.Stopped && trackFinished)
+ {
+ if (chbAutoJump.Checked)
+ PlayNext();
+ else
+ Stop();
+ }
+
if (playerState != PlayerState.Stopped)
{
- int playedMs = (int)playtime.Elapsed.TotalMilliseconds;
+ int playedMs = (int)playtime.Elapsed.TotalMilliseconds + playBeginMs;
int totalMs = (int)(trackLength * 1000);
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
{
@@ -248,6 +298,11 @@ namespace CodeWalker.Forms
}
}
+ private void Timer_Tick(object sender, EventArgs e)
+ {
+ UpdateUI();
+ }
+
private void PlayListView_DoubleClick(object sender, EventArgs e)
{
if (playerState == PlayerState.Playing)
@@ -263,6 +318,25 @@ namespace CodeWalker.Forms
masteringVoice.Dispose();
xAudio2.Dispose();
}
- }
- }
-}
+ }
+
+ private void ExportAsWav_Click(object sender, EventArgs e)
+ {
+ if (PlayListView.SelectedItems.Count == 1)
+ {
+ var item = PlayListView.SelectedItems[0];
+ var audio = item.Tag as AwcAudio;
+
+ saveFileDialog.FileName = audio.Name + ".wav";
+ if (saveFileDialog.ShowDialog() == DialogResult.OK)
+ {
+ Stream wavStream = audio.GetWavStream();
+ FileStream stream = File.Create(saveFileDialog.FileName);
+ wavStream.CopyTo(stream);
+ stream.Close();
+ wavStream.Close();
+ }
+ }
+ }
+ }
+}
diff --git a/Forms/AwcForm.resx b/Forms/AwcForm.resx
index 3badf1f..5fa59c9 100644
--- a/Forms/AwcForm.resx
+++ b/Forms/AwcForm.resx
@@ -117,9 +117,15 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ 99, 17
+
17, 17
+
+ 254, 17
+
diff --git a/GameFiles/FileTypes/AwcFile.cs b/GameFiles/FileTypes/AwcFile.cs
index aeb64d6..2ac8d17 100644
--- a/GameFiles/FileTypes/AwcFile.cs
+++ b/GameFiles/FileTypes/AwcFile.cs
@@ -1,708 +1,792 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using TC = System.ComponentModel.TypeConverterAttribute;
-using EXP = System.ComponentModel.ExpandableObjectConverter;
-
-namespace CodeWalker.GameFiles
-{
- [TC(typeof(EXP))]public class AwcFile : PackedFile
- {
- public string Name { get; set; }
- public RpfFileEntry FileEntry { get; set; }
- public byte[] Data { get; set; }
-
- public string ErrorMessage { get; set; }
-
- public uint Magic { get; set; }
- public ushort Version { get; set; }
- public ushort Flags { get; set; }
- public int StreamCount { get; set; }
- public int InfoOffset { get; set; }
-
- public bool MultiChannel { get; set; }
- public byte[] MultiChannelData { get; set; }
-
- public AwcStreamInfo[] StreamInfos { get; set; }
- public uint[] AudioIds { get; set; }
- public AwcAudio[] Audios { get; set; }
-
- public void Decrypt_RSXXTEA(ref byte[] data, uint[] key)
- {
- // Rockstar's modified version of XXTEA
- uint[] blocks = new uint[data.Length / 4];
- Buffer.BlockCopy(data, 0, blocks, 0, data.Length);
-
- int block_count = blocks.Length;
- uint a, b = blocks[0], i;
-
- i = (uint)(0x9E3779B9 * (6 + 52 / block_count));
- do
- {
- for (int block_index = block_count - 1; block_index >= 0; --block_index)
- {
- a = blocks[(block_index > 0 ? block_index : block_count) - 1];
- b = blocks[block_index] -= (a >> 5 ^ b << 2) + (b >> 3 ^ a << 4) ^ (i ^ b) + (key[block_index & 3 ^ (i >> 2 & 3)] ^ a ^ 0x7B3A207F);
- }
- i -= 0x9E3779B9;
- } while (i != 0);
-
- Buffer.BlockCopy(blocks, 0, data, 0, data.Length);
- }
-
- public void Load(byte[] data, RpfFileEntry entry)
- {
-
- //adapted from libertyV code
-
-
- //MemoryStream ms = new MemoryStream(data);
- Name = entry.Name;
- FileEntry = entry;
- Data = data;
-
- if ((data == null) || (data.Length < 8))
- {
- ErrorMessage = "Data null or too short!";
- return; //nothing to do, not enough data...
- }
-
- Endianess endianess = Endianess.LittleEndian;
-
- Magic = BitConverter.ToUInt32(data, 0);
- if (Magic != 0x54414441 && Magic != 0x41444154)
- {
- if (data.Length % 4 == 0)
- {
- Decrypt_RSXXTEA(ref data, GTA5Keys.PC_AWC_KEY);
- Magic = BitConverter.ToUInt32(data, 0);
- } else
- ErrorMessage = "Corrupted data!";
- }
-
- switch (Magic)
- {
- default:
- ErrorMessage = "Unexpected Magic 0x" + Magic.ToString("X");
- return;
- case 0x54414441:
- endianess = Endianess.LittleEndian;
- break;
- case 0x41444154:
- endianess = Endianess.BigEndian;
- break;
- }
-
- using (MemoryStream ms = new MemoryStream(data))
- {
- DataReader r = new DataReader(ms, endianess);
-
- Magic = r.ReadUInt32();
- Version = r.ReadUInt16();
- Flags = r.ReadUInt16();
- StreamCount = r.ReadInt32();
- InfoOffset = r.ReadInt32();
-
-
- //notes from libertyV:
- // first bit - means that there are unknown word for each stream after this header
- // second bit - I think that it means that not all the tags are in the start of the file, but all the tags of a stream are near the data tag
- // third bit - Multi channel audio
-
- if ((Flags >> 8) != 0xFF)
- {
- ErrorMessage = "Flags 0 not supported!";
- return;
- }
- if ((Flags & 0xF8) != 0)
- {
- //ErrorMessage = "Flags 1 not supported!";
- //return;
- }
-
- MultiChannel = ((Flags & 4) == 4);
-
-
- var flag0 = ((Flags & 1) == 1);
- var infoStart = 16 + (flag0 ? (StreamCount * 2) : 0);
-
- ms.Position = infoStart;
-
- List infos = new List();
- Dictionary infoDict = new Dictionary();
- List audioIds = new List();
- List audios = new List();
-
- for (int i = 0; i < StreamCount; i++)
- {
- var info = new AwcStreamInfo(r);
- infos.Add(info);
- infoDict[info.Id] = info;
- }
- for (int i = 0; i < StreamCount; i++)
- {
- var info = infos[i];
- for (int j = 0; j < info.TagCount; j++)
- {
- var chunk = new AwcChunkInfo(r);
- info.Chunks[chunk.Tag] = chunk;
- }
- }
-
- StreamInfos = infos.ToArray();
-
-
-
- byte hformat = 0xFA;// 250 0x6061D4FA & 0xFF; //JenkHash.GenHash("format");
- byte hdata = 0x55;// 85 0x5EB5E655 & 0xFF; //JenkHash.GenHash("data");
- byte hycd = 0x5C;// 92 YCD resource chunk... lip sync anims?
- byte hunk = 0x36;// 54 unk chunk? small number of bytes (2+)
-
-
-
- if (MultiChannel)
- {
- AwcStreamInfo stream0 = null;
- if (!infoDict.TryGetValue(0, out stream0))
- {
- ErrorMessage = "Couldn't find MultiChannel stream0";
- return;
- }
-
- AwcChunkInfo chunk72 = null;
- if (!stream0.Chunks.TryGetValue(72, out chunk72))
- {
- ErrorMessage = "Couldn't find MultiChannel chunk72";
- return;
- }
-
- ms.Position = chunk72.Offset;
-
- AwcChannelChunkInfo chanInfo = new AwcChannelChunkInfo(r);
- if (chanInfo.ChannelCount != StreamCount - 1)
- {
- ErrorMessage = "Channel Count did not match Stream Count";
- return;
- }
-
- List chunkItems = new List();
- for (int i = 0; i < chanInfo.ChannelCount; i++)
- {
- var itemInfo = new AwcChannelChunkItemInfo(r);
- chunkItems.Add(itemInfo);
- audioIds.Add(infos[i + 1].Id);
- }
-
- //AudioStreams.Add(new MultiChannelAudio(new ChunkStream(this.Stream, streamsChunks[0][Tag("data")]), channelsInfoHeader, streamsInfo, header.BigEndian));
-
- AwcChunkInfo cdata = null;
- if (!stream0.Chunks.TryGetValue(hdata, out cdata))
- {
- ErrorMessage = "Couldn't find Stream 0 data chunk";
- return;
- }
-
- ms.Position = cdata.Offset;
- var lastPos = cdata.Offset + cdata.Size;
- //int chunkSize = 0x800;
- uint bigChunkSize = chanInfo.ChunkSize;
- var chanCount = chanInfo.ChannelCount;
-
- MultiChannelData = r.ReadBytes(cdata.Size);
- ms.Position = cdata.Offset;
-
- //var d = data;//temporary
-
- ////this doesn't seem to work :(
- //while (ms.Position < lastPos)
- //{
- // uint totalChunks = 0;
- // var startPos = ms.Position;
- // var curPos = startPos;
- // //byte[] chunkdata = r.ReadBytes(chunkSize);
- // //ms.Position = startPos;
- // AwcChannelChunkHeader[] chanHeaders = new AwcChannelChunkHeader[chanCount];
- // for (int i = 0; i < chanCount; i++)
- // {
- // var chanHeader = new AwcChannelChunkHeader(r);
- // chanHeaders[i] = chanHeader;
- // totalChunks += chanHeader.ChunkCount;
- // }
- // int headerSize = (int)(totalChunks * 4 + chanInfo.ChannelCount * AwcChannelChunkHeader.Size);
- // headerSize += (((-headerSize) % chunkSize) + chunkSize) % chunkSize; //todo: simplify this!
- // curPos += headerSize;
- // AwcChannelChunk[] chanChunks = new AwcChannelChunk[chanCount];
- // for (int i = 0; i < chanCount; i++)
- // {
- // var chanChunk = new AwcChannelChunk(r, chanHeaders[i], chunkItems[i]);
- // chanChunks[i] = chanChunk;
- // curPos += chanChunk.TotalDataSize;
- // }
- // if (curPos - startPos > chanInfo.ChunkSize)
- // {
- // ErrorMessage = "Chunk was bigger than the chunk size";
- // break;
- // }
- // if ((totalChunks == 0) || ((startPos + chanInfo.ChunkSize) > lastPos))
- // {
- // ErrorMessage = "Unable to read chunk";
- // break;
- // }
- // var newPos = startPos + bigChunkSize;
- // if (newPos >= lastPos) break;
- // ms.Position = newPos;
- //}
-
-
-
- }
- else
- {
-
- for (int i = 0; i < StreamCount; i++)
- {
- var info = infos[i];
-
- AwcChunkInfo cformat = null;
- if (!info.Chunks.TryGetValue(hformat, out cformat))
- {
- ErrorMessage = "Couldn't find Stream " + i.ToString() + " format chunk";
- continue;
- }
-
- AwcChunkInfo cdata = null;
- if (!info.Chunks.TryGetValue(hdata, out cdata))
- {
- ErrorMessage = "Couldn't find Stream " + i.ToString() + " data chunk";
- continue;
- }
-
- AwcChunkInfo cycd = null;
- AwcAudioAnimClipDict oycd = null;
- if (info.Chunks.TryGetValue(hycd, out cycd))
- {
- ms.Position = cycd.Offset;
- oycd = new AwcAudioAnimClipDict(r, cycd);
- }
-
- AwcChunkInfo cunk = null;
- AwcAudioUnk ounk = null;
- if (info.Chunks.TryGetValue(hunk, out cunk))
- {
- ms.Position = cunk.Offset;
- ounk = new AwcAudioUnk(r, cunk);
- }
-
-
- ms.Position = cformat.Offset;
- AwcFormatChunk formatChunk = new AwcFormatChunk(r);
-
- ms.Position = cdata.Offset;
- AwcAudio audio = new AwcAudio(r, info, formatChunk, cdata);
-
- audio.ClipDict = oycd;
- audio.UnkData = ounk;
-
- audios.Add(audio);
- audioIds.Add(info.Id);
- }
- }
-
-
- Audios = audios.ToArray();
- AudioIds = audioIds.ToArray();
-
-
- }
-
- }
-
- }
-
-
- [TC(typeof(EXP))] public class AwcStreamInfo
- {
- public uint RawVal { get; set; }
- public uint TagCount { get; set; }
- public uint Id { get; set; }
-
- public Dictionary Chunks { get; set; } = new Dictionary();
-
- public AwcStreamInfo(DataReader r)
- {
- RawVal = r.ReadUInt32();
- TagCount = (RawVal >> 29);
- Id = (RawVal & 0x1FFFFFFF);
- }
-
- public override string ToString()
- {
- return Id.ToString("X") + ": " + TagCount.ToString() + " tags";
- }
- }
-
- [TC(typeof(EXP))] public class AwcChunkInfo
- {
- public ulong RawVal { get; set; }
- public byte Tag { get; set; }
- public int Size { get; set; }
- public int Offset { get; set; }
-
- public AwcChunkInfo(DataReader r)
- {
- RawVal = r.ReadUInt64();
- Tag = (byte)(RawVal >> 56);
- Size = (int)((RawVal >> 28) & 0x0FFFFFFF);
- Offset = (int)(RawVal & 0x0FFFFFFF);
- }
-
- public override string ToString()
- {
- return Tag.ToString() + ": " + Size.ToString() + ", " + Offset.ToString();
- }
- }
-
- [TC(typeof(EXP))] public class AwcChannelChunkInfo
- {
- public uint Unk0 { get; set; }
- public uint ChunkSize { get; set; }
- public uint ChannelCount { get; set; }
-
- public AwcChannelChunkInfo(DataReader r)
- {
- Unk0 = r.ReadUInt32();
- ChunkSize = r.ReadUInt32();
- ChannelCount = r.ReadUInt32();
- }
-
- public override string ToString()
- {
- return Unk0.ToString() + ": " + ChunkSize.ToString() + ", " + ChannelCount.ToString() + " channels";
- }
- }
-
- [TC(typeof(EXP))] public class AwcChannelChunkItemInfo
- {
- public uint Id { get; set; }
- public uint Samples { get; set; }
- public ushort Unk0 { get; set; }
- public ushort SamplesPerSecond { get; set; }
- public byte Unk1 { get; set; }
- public byte RoundSize { get; set; }
- public ushort Unk2 { get; set; }
-
- public AwcChannelChunkItemInfo(DataReader r)
- {
- Id = r.ReadUInt32();
- Samples = r.ReadUInt32();
- Unk0 = r.ReadUInt16();
- SamplesPerSecond = r.ReadUInt16();
- Unk1 = r.ReadByte();
- RoundSize = r.ReadByte();
- Unk2 = r.ReadUInt16();
- }
-
- public override string ToString()
- {
- return Id.ToString() + ": " + Samples.ToString() + " samples, " + SamplesPerSecond.ToString() + " samples/sec, size: " + RoundSize.ToString();
- }
- }
-
- [TC(typeof(EXP))] public class AwcFormatChunk
- {
- public uint Samples { get; set; }
- public int LoopPoint { get; set; }
- public ushort SamplesPerSecond { get; set; }
- public short Headroom { get; set; }
- public ushort Unk2 { get; set; }
- public ushort Unk3 { get; set; }
- public ushort Unk4 { get; set; }
- public byte Unk5 { get; set; }
- public byte Unk6 { get; set; }
-
- public AwcFormatChunk(DataReader r)
- {
- Samples = r.ReadUInt32();
- LoopPoint = r.ReadInt32();
- SamplesPerSecond = r.ReadUInt16();
- Headroom = r.ReadInt16();
- Unk2 = r.ReadUInt16();
- Unk3 = r.ReadUInt16();
- Unk4 = r.ReadUInt16();
- Unk5 = r.ReadByte();
- Unk6 = r.ReadByte();
-
- //Apparently sometimes this struct is longer? TODO: fix??
- //r.ReadUInt16();
- //r.ReadUInt16();
- }
-
-
- public override string ToString()
- {
- return Headroom.ToString() + ", " + Unk6.ToString() + ": " + Samples.ToString() + " samples, " + SamplesPerSecond.ToString() + " samples/sec";
- }
- }
-
- [TC(typeof(EXP))] public class AwcAudio
- {
- public AwcStreamInfo StreamInfo { get; set; }
- public AwcFormatChunk Format { get; set; }
- public AwcChunkInfo DataInfo { get; set; }
- public byte[] Data { get; set; }
-
- public AwcAudioAnimClipDict ClipDict { get; set; }
- public AwcAudioUnk UnkData { get; set; }
-
-
- public short Channels = 1;
- public short BitsPerSample = 4;//16;
- public int SamplesPerSecond
- {
- get
- {
- return Format?.SamplesPerSecond ?? 0;
- }
- }
- public int SampleCount
- {
- get
- {
- return (int)(Format?.Samples ?? 0);
- }
- }
-
-
- public string Name
- {
- get
- {
- return "0x" + StreamInfo?.Id.ToString("X").PadLeft(8, '0') ?? "0";
- }
- }
- public string Type
- {
- get
- {
- if (Format == null) return "Unknown";
-
- string fmt = "ADPCM";
- switch (Format.Unk6)
- {
- case 4:
- break;
- default:
- break;
- }
-
- var hz = Format?.SamplesPerSecond ?? 0;
-
- return fmt + ((hz > 0) ? (", " + hz.ToString() + " Hz") : "");
- }
- }
-
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TC = System.ComponentModel.TypeConverterAttribute;
+using EXP = System.ComponentModel.ExpandableObjectConverter;
+
+namespace CodeWalker.GameFiles
+{
+ [TC(typeof(EXP))]public class AwcFile : PackedFile
+ {
+ public string Name { get; set; }
+ public RpfFileEntry FileEntry { get; set; }
+ public byte[] Data { get; set; }
+
+ public string ErrorMessage { get; set; }
+
+ public uint Magic { get; set; }
+ public ushort Version { get; set; }
+ public ushort Flags { get; set; }
+ public int StreamCount { get; set; }
+ public int InfoOffset { get; set; }
+
+ public bool MultiChannel { get; set; }
+ public byte[] MultiChannelData { get; set; }
+
+ public AwcStreamInfo[] StreamInfos { get; set; }
+ public uint[] AudioIds { get; set; }
+ public AwcAudio[] Audios { get; set; }
+
+ static public void Decrypt_RSXXTEA(byte[] data, uint[] key)
+ {
+ // Rockstar's modified version of XXTEA
+ uint[] blocks = new uint[data.Length / 4];
+ Buffer.BlockCopy(data, 0, blocks, 0, data.Length);
+
+ int block_count = blocks.Length;
+ uint a, b = blocks[0], i;
+
+ i = (uint)(0x9E3779B9 * (6 + 52 / block_count));
+ do
+ {
+ for (int block_index = block_count - 1; block_index >= 0; --block_index)
+ {
+ a = blocks[(block_index > 0 ? block_index : block_count) - 1];
+ b = blocks[block_index] -= (a >> 5 ^ b << 2) + (b >> 3 ^ a << 4) ^ (i ^ b) + (key[block_index & 3 ^ (i >> 2 & 3)] ^ a ^ 0x7B3A207F);
+ }
+ i -= 0x9E3779B9;
+ } while (i != 0);
+
+ Buffer.BlockCopy(blocks, 0, data, 0, data.Length);
+ }
+
+ public void Load(byte[] data, RpfFileEntry entry)
+ {
+
+ //adapted from libertyV code
+
+
+ //MemoryStream ms = new MemoryStream(data);
+ Name = entry.Name;
+ FileEntry = entry;
+ Data = data;
+
+ if ((data == null) || (data.Length < 8))
+ {
+ ErrorMessage = "Data null or too short!";
+ return; //nothing to do, not enough data...
+ }
+
+ Endianess endianess = Endianess.LittleEndian;
+
+ Magic = BitConverter.ToUInt32(data, 0);
+ if (Magic != 0x54414441 && Magic != 0x41444154)
+ {
+ if (data.Length % 4 == 0)
+ {
+ Decrypt_RSXXTEA(data, GTA5Keys.PC_AWC_KEY);
+ Magic = BitConverter.ToUInt32(data, 0);
+ } else
+ ErrorMessage = "Corrupted data!";
+ }
+
+ switch (Magic)
+ {
+ default:
+ ErrorMessage = "Unexpected Magic 0x" + Magic.ToString("X");
+ return;
+ case 0x54414441:
+ endianess = Endianess.LittleEndian;
+ break;
+ case 0x41444154:
+ endianess = Endianess.BigEndian;
+ break;
+ }
+
+ using (MemoryStream ms = new MemoryStream(data))
+ {
+ DataReader r = new DataReader(ms, endianess);
+
+ Magic = r.ReadUInt32();
+ Version = r.ReadUInt16();
+ Flags = r.ReadUInt16();
+ StreamCount = r.ReadInt32();
+ InfoOffset = r.ReadInt32();
+
+
+ //notes from libertyV:
+ // first bit - means that there are unknown word for each stream after this header
+ // second bit - I think that it means that not all the tags are in the start of the file, but all the tags of a stream are near the data tag
+ // third bit - Multi channel audio
+
+ if ((Flags >> 8) != 0xFF)
+ {
+ ErrorMessage = "Flags 0 not supported!";
+ return;
+ }
+ if ((Flags & 0xF8) != 0)
+ {
+ //ErrorMessage = "Flags 1 not supported!";
+ //return;
+ }
+
+ MultiChannel = ((Flags & 4) == 4);
+
+
+ var flag0 = ((Flags & 1) == 1);
+ var infoStart = 16 + (flag0 ? (StreamCount * 2) : 0);
+
+ ms.Position = infoStart;
+
+ List infos = new List();
+ Dictionary infoDict = new Dictionary();
+ List audioIds = new List();
+ List audios = new List();
+
+ for (int i = 0; i < StreamCount; i++)
+ {
+ var info = new AwcStreamInfo(r);
+ infos.Add(info);
+ infoDict[info.Id] = info;
+ }
+ for (int i = 0; i < StreamCount; i++)
+ {
+ var info = infos[i];
+ for (int j = 0; j < info.TagCount; j++)
+ {
+ var chunk = new AwcChunkInfo(r);
+ info.Chunks[chunk.Tag] = chunk;
+ }
+ }
+
+ StreamInfos = infos.ToArray();
+
+
+
+ byte hformat = 0xFA;// 250 0x6061D4FA & 0xFF; //JenkHash.GenHash("format");
+ byte hdata = 0x55;// 85 0x5EB5E655 & 0xFF; //JenkHash.GenHash("data");
+ byte hycd = 0x5C;// 92 YCD resource chunk... lip sync anims?
+ byte hunk = 0x36;// 54 unk chunk? small number of bytes (2+)
+
+
+
+ if (MultiChannel)
+ {
+ AwcStreamInfo stream0 = null;
+ if (!infoDict.TryGetValue(0, out stream0))
+ {
+ ErrorMessage = "Couldn't find MultiChannel stream0";
+ return;
+ }
+
+ AwcChunkInfo chunk72 = null;
+ if (!stream0.Chunks.TryGetValue(72, out chunk72))
+ {
+ ErrorMessage = "Couldn't find MultiChannel chunk72";
+ return;
+ }
+
+ ms.Position = chunk72.Offset;
+
+ AwcChannelChunkInfo chanInfo = new AwcChannelChunkInfo(r);
+ if (chanInfo.ChannelCount != StreamCount - 1)
+ {
+ ErrorMessage = "Channel Count did not match Stream Count";
+ return;
+ }
+
+ List chunkItems = new List();
+ for (int i = 0; i < chanInfo.ChannelCount; i++)
+ {
+ var itemInfo = new AwcChannelChunkItemInfo(r);
+ chunkItems.Add(itemInfo);
+ audioIds.Add(infos[i + 1].Id);
+ }
+
+ //AudioStreams.Add(new MultiChannelAudio(new ChunkStream(this.Stream, streamsChunks[0][Tag("data")]), channelsInfoHeader, streamsInfo, header.BigEndian));
+
+ AwcChunkInfo cdata = null;
+ if (!stream0.Chunks.TryGetValue(hdata, out cdata))
+ {
+ ErrorMessage = "Couldn't find Stream 0 data chunk";
+ return;
+ }
+
+ ms.Position = cdata.Offset;
+ var lastPos = cdata.Offset + cdata.Size;
+ //int chunkSize = 0x800;
+ uint bigChunkSize = chanInfo.ChunkSize;
+ var chanCount = chanInfo.ChannelCount;
+
+ MultiChannelData = r.ReadBytes(cdata.Size);
+ ms.Position = cdata.Offset;
+
+ //var d = data;//temporary
+
+ ////this doesn't seem to work :(
+ //while (ms.Position < lastPos)
+ //{
+ // uint totalChunks = 0;
+ // var startPos = ms.Position;
+ // var curPos = startPos;
+ // //byte[] chunkdata = r.ReadBytes(chunkSize);
+ // //ms.Position = startPos;
+ // AwcChannelChunkHeader[] chanHeaders = new AwcChannelChunkHeader[chanCount];
+ // for (int i = 0; i < chanCount; i++)
+ // {
+ // var chanHeader = new AwcChannelChunkHeader(r);
+ // chanHeaders[i] = chanHeader;
+ // totalChunks += chanHeader.ChunkCount;
+ // }
+ // int headerSize = (int)(totalChunks * 4 + chanInfo.ChannelCount * AwcChannelChunkHeader.Size);
+ // headerSize += (((-headerSize) % chunkSize) + chunkSize) % chunkSize; //todo: simplify this!
+ // curPos += headerSize;
+ // AwcChannelChunk[] chanChunks = new AwcChannelChunk[chanCount];
+ // for (int i = 0; i < chanCount; i++)
+ // {
+ // var chanChunk = new AwcChannelChunk(r, chanHeaders[i], chunkItems[i]);
+ // chanChunks[i] = chanChunk;
+ // curPos += chanChunk.TotalDataSize;
+ // }
+ // if (curPos - startPos > chanInfo.ChunkSize)
+ // {
+ // ErrorMessage = "Chunk was bigger than the chunk size";
+ // break;
+ // }
+ // if ((totalChunks == 0) || ((startPos + chanInfo.ChunkSize) > lastPos))
+ // {
+ // ErrorMessage = "Unable to read chunk";
+ // break;
+ // }
+ // var newPos = startPos + bigChunkSize;
+ // if (newPos >= lastPos) break;
+ // ms.Position = newPos;
+ //}
+
+
+
+ }
+ else
+ {
+
+ for (int i = 0; i < StreamCount; i++)
+ {
+ var info = infos[i];
+
+ AwcChunkInfo cformat = null;
+ if (!info.Chunks.TryGetValue(hformat, out cformat))
+ {
+ ErrorMessage = "Couldn't find Stream " + i.ToString() + " format chunk";
+ continue;
+ }
+
+ AwcChunkInfo cdata = null;
+ if (!info.Chunks.TryGetValue(hdata, out cdata))
+ {
+ ErrorMessage = "Couldn't find Stream " + i.ToString() + " data chunk";
+ continue;
+ }
+
+ AwcChunkInfo cycd = null;
+ AwcAudioAnimClipDict oycd = null;
+ if (info.Chunks.TryGetValue(hycd, out cycd))
+ {
+ ms.Position = cycd.Offset;
+ oycd = new AwcAudioAnimClipDict(r, cycd);
+ }
+
+ AwcChunkInfo cunk = null;
+ AwcAudioUnk ounk = null;
+ if (info.Chunks.TryGetValue(hunk, out cunk))
+ {
+ ms.Position = cunk.Offset;
+ ounk = new AwcAudioUnk(r, cunk);
+ }
+
+
+ ms.Position = cformat.Offset;
+ AwcFormatChunk formatChunk = new AwcFormatChunk(r);
+
+ ms.Position = cdata.Offset;
+ AwcAudio audio = new AwcAudio(r, info, formatChunk, cdata);
+
+ audio.ClipDict = oycd;
+ audio.UnkData = ounk;
+
+ audios.Add(audio);
+ audioIds.Add(info.Id);
+ }
+ }
+
+
+ Audios = audios.ToArray();
+ AudioIds = audioIds.ToArray();
+
+
+ }
+
+ }
+
+ }
+
+
+ [TC(typeof(EXP))] public class AwcStreamInfo
+ {
+ public uint RawVal { get; set; }
+ public uint TagCount { get; set; }
+ public uint Id { get; set; }
+
+ public Dictionary Chunks { get; set; } = new Dictionary();
+
+ public AwcStreamInfo(DataReader r)
+ {
+ RawVal = r.ReadUInt32();
+ TagCount = (RawVal >> 29);
+ Id = (RawVal & 0x1FFFFFFF);
+ }
+
+ public override string ToString()
+ {
+ return Id.ToString("X") + ": " + TagCount.ToString() + " tags";
+ }
+ }
+
+ [TC(typeof(EXP))] public class AwcChunkInfo
+ {
+ public ulong RawVal { get; set; }
+ public byte Tag { get; set; }
+ public int Size { get; set; }
+ public int Offset { get; set; }
+
+ public AwcChunkInfo(DataReader r)
+ {
+ RawVal = r.ReadUInt64();
+ Tag = (byte)(RawVal >> 56);
+ Size = (int)((RawVal >> 28) & 0x0FFFFFFF);
+ Offset = (int)(RawVal & 0x0FFFFFFF);
+ }
+
+ public override string ToString()
+ {
+ return Tag.ToString() + ": " + Size.ToString() + ", " + Offset.ToString();
+ }
+ }
+
+ [TC(typeof(EXP))] public class AwcChannelChunkInfo
+ {
+ public uint Unk0 { get; set; }
+ public uint ChunkSize { get; set; }
+ public uint ChannelCount { get; set; }
+
+ public AwcChannelChunkInfo(DataReader r)
+ {
+ Unk0 = r.ReadUInt32();
+ ChunkSize = r.ReadUInt32();
+ ChannelCount = r.ReadUInt32();
+ }
+
+ public override string ToString()
+ {
+ return Unk0.ToString() + ": " + ChunkSize.ToString() + ", " + ChannelCount.ToString() + " channels";
+ }
+ }
+
+ [TC(typeof(EXP))] public class AwcChannelChunkItemInfo
+ {
+ public uint Id { get; set; }
+ public uint Samples { get; set; }
+ public ushort Unk0 { get; set; }
+ public ushort SamplesPerSecond { get; set; }
+ public byte Unk1 { get; set; }
+ public byte RoundSize { get; set; }
+ public ushort Unk2 { get; set; }
+
+ public AwcChannelChunkItemInfo(DataReader r)
+ {
+ Id = r.ReadUInt32();
+ Samples = r.ReadUInt32();
+ Unk0 = r.ReadUInt16();
+ SamplesPerSecond = r.ReadUInt16();
+ Unk1 = r.ReadByte();
+ RoundSize = r.ReadByte();
+ Unk2 = r.ReadUInt16();
+ }
+
+ public override string ToString()
+ {
+ return Id.ToString() + ": " + Samples.ToString() + " samples, " + SamplesPerSecond.ToString() + " samples/sec, size: " + RoundSize.ToString();
+ }
+ }
+
+ [TC(typeof(EXP))] public class AwcFormatChunk
+ {
+ public uint Samples { get; set; }
+ public int LoopPoint { get; set; }
+ public ushort SamplesPerSecond { get; set; }
+ public short Headroom { get; set; }
+ public ushort LoopBegin { get; set; }
+ public ushort LoopEnd { get; set; }
+ public ushort PlayEnd { get; set; }
+ public byte PlayBegin { get; set; }
+
+ public enum CodecFormat {
+ PCM = 0,
+ ADPCM = 4
+ }
+ public CodecFormat Codec { get; set; }
+
+ public AwcFormatChunk(DataReader r)
+ {
+ Samples = r.ReadUInt32();
+ LoopPoint = r.ReadInt32();
+ SamplesPerSecond = r.ReadUInt16();
+ Headroom = r.ReadInt16();
+ LoopBegin = r.ReadUInt16();
+ LoopEnd = r.ReadUInt16();
+ PlayEnd = r.ReadUInt16();
+ PlayBegin = r.ReadByte();
+ Codec = (CodecFormat)r.ReadByte();
+
+ //Apparently sometimes this struct is longer? TODO: fix??
+ //r.ReadUInt16();
+ //r.ReadUInt16();
+ }
+
+
+ public override string ToString()
+ {
+ return Headroom.ToString() + ", " + Codec.ToString() + ": " + Samples.ToString() + " samples, " + SamplesPerSecond.ToString() + " samples/sec";
+ }
+ }
+
+ [TC(typeof(EXP))] public class AwcAudio
+ {
+ public AwcStreamInfo StreamInfo { get; set; }
+ public AwcFormatChunk Format { get; set; }
+ public AwcChunkInfo DataInfo { get; set; }
+ public byte[] Data { get; set; }
+
+ public AwcAudioAnimClipDict ClipDict { get; set; }
+ public AwcAudioUnk UnkData { get; set; }
+
+
+ public short Channels = 1;
+ public short BitsPerSample = 16;
+ public int SamplesPerSecond
+ {
+ get
+ {
+ return Format?.SamplesPerSecond ?? 0;
+ }
+ }
+ public int SampleCount
+ {
+ get
+ {
+ return (int)(Format?.Samples ?? 0);
+ }
+ }
+
+
+ public string Name
+ {
+ get
+ {
+ return "0x" + StreamInfo?.Id.ToString("X").PadLeft(8, '0') ?? "0";
+ }
+ }
+ public string Type
+ {
+ get
+ {
+ if (Format == null) return "Unknown";
+
+ string codec;
+ switch (Format.Codec)
+ {
+ case AwcFormatChunk.CodecFormat.PCM:
+ codec = "PCM";
+ break;
+ case AwcFormatChunk.CodecFormat.ADPCM:
+ codec = "ADPCM";
+ break;
+ default:
+ codec = "Unknown";
+ break;
+ }
+
+ var hz = Format.SamplesPerSecond;
+
+ return codec + ((hz > 0) ? (", " + hz.ToString() + " Hz") : "");
+ }
+ }
+
public float Length
{
- get
- {
- return Format == null ? 0 : (float)Format.Samples / Format.SamplesPerSecond;
+ get
+ {
+ return Format == null ? 0 : (float)Format.Samples / Format.SamplesPerSecond;
}
- }
-
- public string LengthStr
- {
- get
- {
- return TimeSpan.FromSeconds(Length).ToString("m\\:ss");
- }
- }
-
-
- public AwcAudio(DataReader r, AwcStreamInfo s, AwcFormatChunk f, AwcChunkInfo d)
- {
- StreamInfo = s;
- Format = f;
- DataInfo = d;
-
- Data = r.ReadBytes(d.Size);
- }
-
- public override string ToString()
- {
- var hash = (StreamInfo?.Id.ToString("X") ?? "0").PadLeft(8, '0');
- return "0x" + hash + ": " + Format?.ToString() ?? "AwcAudio";
- }
-
-
-
- public Stream GetWavStream()
- {
- MemoryStream stream = new MemoryStream();
- BinaryWriter w = new BinaryWriter(stream);
-
-
- //see http://icculus.org/SDL_sound/downloads/external_documentation/wavecomp.htm
- //see https://github.com/naudio/NAudio/blob/master/NAudio/Wave/WaveFormats/AdpcmWaveFormat.cs
- //see https://msdn.microsoft.com/en-us/library/windows/desktop/ff538799(v=vs.85).aspx
-
-
- int samplesPerSec = SamplesPerSecond;
-
- Channels = 1;
- BitsPerSample = 16;
- int byteRate = samplesPerSec * Channels * BitsPerSample / 8;
- short blockAlign = (short)(Channels * BitsPerSample / 8);
+ }
+
+ public string LengthStr
+ {
+ get
+ {
+ return TimeSpan.FromSeconds(Length).ToString("m\\:ss");
+ }
+ }
+
+ public AwcAudio(DataReader r, AwcStreamInfo s, AwcFormatChunk f, AwcChunkInfo d)
+ {
+ StreamInfo = s;
+ Format = f;
+ DataInfo = d;
+
+ Data = r.ReadBytes(d.Size);
+ }
+
+ public override string ToString()
+ {
+ var hash = (StreamInfo?.Id.ToString("X") ?? "0").PadLeft(8, '0');
+ return "0x" + hash + ": " + Format?.ToString() ?? "AwcAudio";
+ }
+
+ public byte[] DecodeADPCM(byte[] data, int sampleCount)
+ {
+ byte[] dataPCM = new byte[data.Length * 4];
+ int predictor = 0, step_index = 0, step = 0;
+ int readingOffset = 0, writingOffset = 0, bytesInBlock = 0;
+
+ int[] ima_index_table = {
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8
+ };
+
+ short[] ima_step_table = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+ };
+
+ int clip(int value, int min, int max)
+ {
+ if (value < min)
+ return min;
+ if (value > max)
+ return max;
+ return value;
+ }
+
+ void parseNibble(byte nibble)
+ {
+ step_index = clip(step_index + ima_index_table[nibble], 0, 88);
+
+ int diff = step >> 3;
+ if ((nibble & 4) > 0) diff += step;
+ if ((nibble & 2) > 0) diff += step >> 1;
+ if ((nibble & 1) > 0) diff += step >> 2;
+ if ((nibble & 8) > 0) predictor -= diff;
+ else predictor += diff;
+
+ step = ima_step_table[step_index];
+
+ int samplePCM = clip(predictor, -32768, 32767);
+ dataPCM[writingOffset] = (byte)(samplePCM & 0xFF);
+ dataPCM[writingOffset + 1] = (byte)((samplePCM >> 8) & 0xFF);
+ writingOffset += 2;
+ }
+
+ while ((readingOffset < data.Length) && (sampleCount > 0))
+ {
+ if (bytesInBlock == 0)
+ {
+ step_index = clip(data[readingOffset], 0, 88);
+ predictor = BitConverter.ToInt16(data, readingOffset + 2);
+ step = ima_step_table[step_index];
+ bytesInBlock = 2044;
+ readingOffset += 4;
+ }
+ else
+ {
+ parseNibble((byte)(data[readingOffset] & 0x0F));
+ parseNibble((byte)((data[readingOffset] >> 4) & 0x0F));
+ bytesInBlock--;
+ sampleCount -= 2;
+ readingOffset++;
+ }
+ }
+
+ return dataPCM;
+ }
+
+ public Stream GetWavStream()
+ {
+ byte[] dataPCM = null;
+ int bitsPerSample = BitsPerSample;
+
+ switch (Format.Codec)
+ {
+ case AwcFormatChunk.CodecFormat.PCM:
+ dataPCM = Data;
+ break;
+ case AwcFormatChunk.CodecFormat.ADPCM:
+ dataPCM = new byte[Data.Length];
+ Buffer.BlockCopy(Data, 0, dataPCM, 0, Data.Length);
+ AwcFile.Decrypt_RSXXTEA(dataPCM, GTA5Keys.PC_AWC_KEY);
+ dataPCM = DecodeADPCM(dataPCM, SampleCount);
+ bitsPerSample = 16;
+ break;
+ }
+
+ int byteRate = SamplesPerSecond * Channels * bitsPerSample / 8;
+ short blockAlign = (short)(Channels * bitsPerSample / 8);
+
+ MemoryStream stream = new MemoryStream();
+ BinaryWriter w = new BinaryWriter(stream);
+ int wavLength = 12 + 24 + 8 + Data.Length;
// 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
+ w.Write("RIFF".ToCharArray());
+ w.Write((int)(wavLength - 8));
+ w.Write("WAVE".ToCharArray());
+
+ // fmt sub-chunk
+ w.Write("fmt ".ToCharArray());
+ w.Write((int)16); // fmt size
+ w.Write((short)1); // 1 = WAVE_FORMAT_PCM
+ w.Write((short)Channels);
+ w.Write((int)SamplesPerSecond);
+ w.Write((int)byteRate);
+ w.Write((short)blockAlign);
+ w.Write((short)bitsPerSample);
// data sub-chunk
- w.Write("data".ToCharArray());
- w.Write(Data.Length);
- w.Write(Data);
-
- w.Flush();
-
- stream.Position = 0;
- return stream;
- }
-
-
-
- }
-
- [TC(typeof(EXP))] public class AwcAudioAnimClipDict
- {
- public byte[] Data { get; set; }
- public ClipDictionary ClipDict { get; set; }
-
- public AwcAudioAnimClipDict(DataReader r, AwcChunkInfo info)
- {
- Data = r.ReadBytes(info.Size);
-
- if ((Data == null) || (Data.Length < 16)) return;
-
- var data = Data;
-
- RpfResourceFileEntry resentry = new RpfResourceFileEntry();
- uint rsc7 = BitConverter.ToUInt32(data, 0);
- int version = BitConverter.ToInt32(data, 4);
- resentry.SystemFlags = BitConverter.ToUInt32(data, 8);
- resentry.GraphicsFlags = BitConverter.ToUInt32(data, 12);
-
- if (rsc7 != 0x37435352)
- { } //testing..
- if (version != 46) //46 is Clip Dictionary...
- { }
-
- int newlen = data.Length - 16; //trim the header from the data passed to the next step.
- int arrlen = Math.Max(newlen, resentry.SystemSize + resentry.GraphicsSize);//expand it as necessary for the reader.
- byte[] newdata = new byte[arrlen];
- Buffer.BlockCopy(data, 16, newdata, 0, newlen);
- data = newdata;
-
- ResourceDataReader rd = new ResourceDataReader(resentry, data);
-
- ClipDict = rd.ReadBlock();
-
-
- }
-
- public override string ToString()
- {
- return (ClipDict?.ClipsMapEntries ?? 0).ToString() + " entries";
- }
- }
-
- [TC(typeof(EXP))] public class AwcAudioUnk
- {
- public byte[] Data { get; set; }
-
- public AwcAudioUnk(DataReader r, AwcChunkInfo info)
- {
- Data = r.ReadBytes(info.Size);
- }
-
- public override string ToString()
- {
- if (Data == null) return "";
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < Data.Length; i++)
- {
- if (sb.Length > 0) sb.Append(' ');
- sb.Append(Data[i].ToString());
- }
- return sb.ToString();
- }
- }
-
-
- [TC(typeof(EXP))] public class AwcChannelChunkHeader
- {
- public static uint Size = 16; //24 for ps3...
-
- public uint StartChunk { get; set; }
- public uint ChunkCount { get; set; }
- public uint SamplesToSkip { get; set; } //mostly 0
- public uint SamplesPerChunk { get; set; }
- public uint DataSize { get; set; }
-
- public AwcChannelChunkHeader(DataReader r)
- {
- StartChunk = r.ReadUInt32();
- ChunkCount = r.ReadUInt32();
- SamplesToSkip = r.ReadUInt32();
- SamplesPerChunk = r.ReadUInt32();
- DataSize = ChunkCount * 0x800;
-
- //for ps3, two extra ints:
- //uint unk0 = r.ReadUint32();
- //DataSize = r.ReadUint32();
-
-
- }
-
- }
-
- [TC(typeof(EXP))] public class AwcChannelChunk
- {
- public AwcChannelChunkHeader Header { get; set; }
- public AwcChannelChunkItemInfo Info { get; set; }
- public byte[] Data { get; set; }
-
- public uint TotalDataSize { get; set; }
-
- public AwcChannelChunk(DataReader r, AwcChannelChunkHeader h, AwcChannelChunkItemInfo i)
- {
- Header = h;
- Info = i;
-
- TotalDataSize = h.DataSize;
-
- var rs = i?.RoundSize ?? 0;
- int ds = (int)h.DataSize;
- if (rs != 0)
- {
- TotalDataSize = (uint)(TotalDataSize + (((-ds) % rs) + rs) % rs);
- }
- }
-
- }
-
-}
+ w.Write("data".ToCharArray());
+ w.Write((int)dataPCM.Length);
+ w.Write(dataPCM);
+
+ w.Flush();
+ stream.Position = 0;
+ return stream;
+ }
+ }
+
+ [TC(typeof(EXP))] public class AwcAudioAnimClipDict
+ {
+ public byte[] Data { get; set; }
+ public ClipDictionary ClipDict { get; set; }
+
+ public AwcAudioAnimClipDict(DataReader r, AwcChunkInfo info)
+ {
+ Data = r.ReadBytes(info.Size);
+
+ if ((Data == null) || (Data.Length < 16)) return;
+
+ var data = Data;
+
+ RpfResourceFileEntry resentry = new RpfResourceFileEntry();
+ uint rsc7 = BitConverter.ToUInt32(data, 0);
+ int version = BitConverter.ToInt32(data, 4);
+ resentry.SystemFlags = BitConverter.ToUInt32(data, 8);
+ resentry.GraphicsFlags = BitConverter.ToUInt32(data, 12);
+
+ if (rsc7 != 0x37435352)
+ { } //testing..
+ if (version != 46) //46 is Clip Dictionary...
+ { }
+
+ int newlen = data.Length - 16; //trim the header from the data passed to the next step.
+ int arrlen = Math.Max(newlen, resentry.SystemSize + resentry.GraphicsSize);//expand it as necessary for the reader.
+ byte[] newdata = new byte[arrlen];
+ Buffer.BlockCopy(data, 16, newdata, 0, newlen);
+ data = newdata;
+
+ ResourceDataReader rd = new ResourceDataReader(resentry, data);
+
+ ClipDict = rd.ReadBlock();
+
+
+ }
+
+ public override string ToString()
+ {
+ return (ClipDict?.ClipsMapEntries ?? 0).ToString() + " entries";
+ }
+ }
+
+ [TC(typeof(EXP))] public class AwcAudioUnk
+ {
+ public byte[] Data { get; set; }
+
+ public AwcAudioUnk(DataReader r, AwcChunkInfo info)
+ {
+ Data = r.ReadBytes(info.Size);
+ }
+
+ public override string ToString()
+ {
+ if (Data == null) return "";
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < Data.Length; i++)
+ {
+ if (sb.Length > 0) sb.Append(' ');
+ sb.Append(Data[i].ToString());
+ }
+ return sb.ToString();
+ }
+ }
+
+
+ [TC(typeof(EXP))] public class AwcChannelChunkHeader
+ {
+ public static uint Size = 16; //24 for ps3...
+
+ public uint StartChunk { get; set; }
+ public uint ChunkCount { get; set; }
+ public uint SamplesToSkip { get; set; } //mostly 0
+ public uint SamplesPerChunk { get; set; }
+ public uint DataSize { get; set; }
+
+ public AwcChannelChunkHeader(DataReader r)
+ {
+ StartChunk = r.ReadUInt32();
+ ChunkCount = r.ReadUInt32();
+ SamplesToSkip = r.ReadUInt32();
+ SamplesPerChunk = r.ReadUInt32();
+ DataSize = ChunkCount * 0x800;
+
+ //for ps3, two extra ints:
+ //uint unk0 = r.ReadUint32();
+ //DataSize = r.ReadUint32();
+
+
+ }
+
+ }
+
+ [TC(typeof(EXP))] public class AwcChannelChunk
+ {
+ public AwcChannelChunkHeader Header { get; set; }
+ public AwcChannelChunkItemInfo Info { get; set; }
+ public byte[] Data { get; set; }
+
+ public uint TotalDataSize { get; set; }
+
+ public AwcChannelChunk(DataReader r, AwcChannelChunkHeader h, AwcChannelChunkItemInfo i)
+ {
+ Header = h;
+ Info = i;
+
+ TotalDataSize = h.DataSize;
+
+ var rs = i?.RoundSize ?? 0;
+ int ds = (int)h.DataSize;
+ if (rs != 0)
+ {
+ TotalDataSize = (uint)(TotalDataSize + (((-ds) % rs) + rs) % rs);
+ }
+ }
+
+ }
+
+}