diff --git a/ProjectManager/ProjectManager.Designer.cs b/ProjectManager/ProjectManager.Designer.cs index 83bb101c..d1d28e43 100644 --- a/ProjectManager/ProjectManager.Designer.cs +++ b/ProjectManager/ProjectManager.Designer.cs @@ -38,14 +38,15 @@ private void InitializeComponent() this.label1 = new System.Windows.Forms.Label(); this.buttonProjectDetails = new System.Windows.Forms.Button(); this.buttonExportRenoise = new System.Windows.Forms.Button(); + this.buttonExportReaper = new System.Windows.Forms.Button(); this.SuspendLayout(); // // buttonOpenProject // - this.buttonOpenProject.Location = new System.Drawing.Point(32, 29); - this.buttonOpenProject.Margin = new System.Windows.Forms.Padding(8, 7, 8, 7); + this.buttonOpenProject.Location = new System.Drawing.Point(16, 15); + this.buttonOpenProject.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.buttonOpenProject.Name = "buttonOpenProject"; - this.buttonOpenProject.Size = new System.Drawing.Size(277, 55); + this.buttonOpenProject.Size = new System.Drawing.Size(138, 28); this.buttonOpenProject.TabIndex = 0; this.buttonOpenProject.Text = "Open Project"; this.buttonOpenProject.UseVisualStyleBackColor = true; @@ -54,10 +55,10 @@ private void InitializeComponent() // buttonSaveHeader // this.buttonSaveHeader.Enabled = false; - this.buttonSaveHeader.Location = new System.Drawing.Point(32, 329); - this.buttonSaveHeader.Margin = new System.Windows.Forms.Padding(8, 7, 8, 7); + this.buttonSaveHeader.Location = new System.Drawing.Point(16, 170); + this.buttonSaveHeader.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.buttonSaveHeader.Name = "buttonSaveHeader"; - this.buttonSaveHeader.Size = new System.Drawing.Size(277, 55); + this.buttonSaveHeader.Size = new System.Drawing.Size(138, 28); this.buttonSaveHeader.TabIndex = 0; this.buttonSaveHeader.Text = "Save C++ Header"; this.buttonSaveHeader.UseVisualStyleBackColor = true; @@ -66,10 +67,10 @@ private void InitializeComponent() // buttonSaveBinary // this.buttonSaveBinary.Enabled = false; - this.buttonSaveBinary.Location = new System.Drawing.Point(32, 398); - this.buttonSaveBinary.Margin = new System.Windows.Forms.Padding(8, 7, 8, 7); + this.buttonSaveBinary.Location = new System.Drawing.Point(16, 205); + this.buttonSaveBinary.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.buttonSaveBinary.Name = "buttonSaveBinary"; - this.buttonSaveBinary.Size = new System.Drawing.Size(277, 55); + this.buttonSaveBinary.Size = new System.Drawing.Size(138, 28); this.buttonSaveBinary.TabIndex = 0; this.buttonSaveBinary.Text = "Save Binary Song"; this.buttonSaveBinary.UseVisualStyleBackColor = true; @@ -78,10 +79,10 @@ private void InitializeComponent() // buttonPlaySong // this.buttonPlaySong.Enabled = false; - this.buttonPlaySong.Location = new System.Drawing.Point(32, 215); - this.buttonPlaySong.Margin = new System.Windows.Forms.Padding(8, 7, 8, 7); + this.buttonPlaySong.Location = new System.Drawing.Point(16, 111); + this.buttonPlaySong.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.buttonPlaySong.Name = "buttonPlaySong"; - this.buttonPlaySong.Size = new System.Drawing.Size(277, 55); + this.buttonPlaySong.Size = new System.Drawing.Size(138, 28); this.buttonPlaySong.TabIndex = 0; this.buttonPlaySong.Text = "Play Song"; this.buttonPlaySong.UseVisualStyleBackColor = true; @@ -90,10 +91,10 @@ private void InitializeComponent() // buttonExportWav // this.buttonExportWav.Enabled = false; - this.buttonExportWav.Location = new System.Drawing.Point(32, 467); - this.buttonExportWav.Margin = new System.Windows.Forms.Padding(8, 7, 8, 7); + this.buttonExportWav.Location = new System.Drawing.Point(16, 241); + this.buttonExportWav.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.buttonExportWav.Name = "buttonExportWav"; - this.buttonExportWav.Size = new System.Drawing.Size(277, 55); + this.buttonExportWav.Size = new System.Drawing.Size(138, 28); this.buttonExportWav.TabIndex = 0; this.buttonExportWav.Text = "Export Wav"; this.buttonExportWav.UseVisualStyleBackColor = true; @@ -104,31 +105,31 @@ private void InitializeComponent() this.textBoxOutput.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxOutput.Location = new System.Drawing.Point(325, 67); - this.textBoxOutput.Margin = new System.Windows.Forms.Padding(8, 7, 8, 7); + this.textBoxOutput.Location = new System.Drawing.Point(162, 35); + this.textBoxOutput.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.textBoxOutput.Multiline = true; this.textBoxOutput.Name = "textBoxOutput"; this.textBoxOutput.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.textBoxOutput.Size = new System.Drawing.Size(1135, 655); + this.textBoxOutput.Size = new System.Drawing.Size(570, 402); this.textBoxOutput.TabIndex = 2; // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(325, 29); - this.label1.Margin = new System.Windows.Forms.Padding(8, 0, 8, 0); + this.label1.Location = new System.Drawing.Point(162, 15); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(286, 32); + this.label1.Size = new System.Drawing.Size(143, 17); this.label1.TabIndex = 3; this.label1.Text = "Conversion Warnings"; // // buttonProjectDetails // this.buttonProjectDetails.Enabled = false; - this.buttonProjectDetails.Location = new System.Drawing.Point(29, 98); - this.buttonProjectDetails.Margin = new System.Windows.Forms.Padding(8, 7, 8, 7); + this.buttonProjectDetails.Location = new System.Drawing.Point(14, 51); + this.buttonProjectDetails.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.buttonProjectDetails.Name = "buttonProjectDetails"; - this.buttonProjectDetails.Size = new System.Drawing.Size(277, 55); + this.buttonProjectDetails.Size = new System.Drawing.Size(138, 28); this.buttonProjectDetails.TabIndex = 4; this.buttonProjectDetails.Text = "Project Details"; this.buttonProjectDetails.UseVisualStyleBackColor = true; @@ -137,23 +138,36 @@ private void InitializeComponent() // buttonExportRenoise // this.buttonExportRenoise.Enabled = false; - this.buttonExportRenoise.Location = new System.Drawing.Point(32, 636); - this.buttonExportRenoise.Margin = new System.Windows.Forms.Padding(8, 7, 8, 7); + this.buttonExportRenoise.Location = new System.Drawing.Point(16, 341); + this.buttonExportRenoise.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.buttonExportRenoise.Name = "buttonExportRenoise"; - this.buttonExportRenoise.Size = new System.Drawing.Size(277, 86); + this.buttonExportRenoise.Size = new System.Drawing.Size(138, 44); this.buttonExportRenoise.TabIndex = 0; this.buttonExportRenoise.Text = "Export Renoise Patch Song"; this.buttonExportRenoise.UseVisualStyleBackColor = true; this.buttonExportRenoise.Click += new System.EventHandler(this.buttonExportRenoise_Click); // + // buttonExportReaper + // + this.buttonExportReaper.Enabled = false; + this.buttonExportReaper.Location = new System.Drawing.Point(16, 393); + this.buttonExportReaper.Margin = new System.Windows.Forms.Padding(4); + this.buttonExportReaper.Name = "buttonExportReaper"; + this.buttonExportReaper.Size = new System.Drawing.Size(138, 44); + this.buttonExportReaper.TabIndex = 0; + this.buttonExportReaper.Text = "Export Reaper Patch Song"; + this.buttonExportReaper.UseVisualStyleBackColor = true; + this.buttonExportReaper.Click += new System.EventHandler(this.buttonExportReaper_Click); + // // ProjectManager // - this.AutoScaleDimensions = new System.Drawing.SizeF(16F, 31F); + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(1499, 756); + this.ClientSize = new System.Drawing.Size(750, 452); this.Controls.Add(this.buttonProjectDetails); this.Controls.Add(this.label1); this.Controls.Add(this.textBoxOutput); + this.Controls.Add(this.buttonExportReaper); this.Controls.Add(this.buttonExportRenoise); this.Controls.Add(this.buttonExportWav); this.Controls.Add(this.buttonPlaySong); @@ -161,7 +175,7 @@ private void InitializeComponent() this.Controls.Add(this.buttonSaveHeader); this.Controls.Add(this.buttonOpenProject); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.Margin = new System.Windows.Forms.Padding(8, 7, 8, 7); + this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.Name = "ProjectManager"; this.Text = "Project Manager"; this.ResumeLayout(false); @@ -180,6 +194,7 @@ private void InitializeComponent() private System.Windows.Forms.Label label1; private System.Windows.Forms.Button buttonProjectDetails; private System.Windows.Forms.Button buttonExportRenoise; + private System.Windows.Forms.Button buttonExportReaper; } } diff --git a/ProjectManager/ProjectManager.cs b/ProjectManager/ProjectManager.cs index 32252e52..bb091e98 100644 --- a/ProjectManager/ProjectManager.cs +++ b/ProjectManager/ProjectManager.cs @@ -42,8 +42,7 @@ private void OpenProject(string projectFile) catch (Exception err) { MessageBox.Show(err.Message); - } - + } } private void OnLogEvent(object sender, EventArgs e) @@ -60,6 +59,7 @@ private void Enable() buttonExportWav.Enabled = true; buttonProjectDetails.Enabled = true; buttonExportRenoise.Enabled = true; + buttonExportReaper.Enabled = true; } private void buttonSaveHeader_Click(object sender, EventArgs e) @@ -176,5 +176,26 @@ private void buttonExportRenoise_Click(object sender, EventArgs e) MessageBox.Show(err.Message); } } + + private void buttonExportReaper_Click(object sender, EventArgs e) + { + try + { + var inject = new ReaperInject(); + var project = inject.InjectPatches(song, logger); + + var sfd = new SaveFileDialog(); + sfd.Filter = "Reaper Song File|*.rpp"; + sfd.FileName = fileName; + if (sfd.ShowDialog() == DialogResult.OK) + { + File.WriteAllText(sfd.FileName, project); + } + } + catch (Exception err) + { + MessageBox.Show(err.Message); + } + } } } diff --git a/WaveSabreConvert/Properties/Resources.Designer.cs b/WaveSabreConvert/Properties/Resources.Designer.cs index 2610829e..4ab27425 100644 --- a/WaveSabreConvert/Properties/Resources.Designer.cs +++ b/WaveSabreConvert/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace WaveSabreConvert.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -60,6 +60,36 @@ internal Resources() { } } + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] ReaperDevices { + get { + object obj = ResourceManager.GetObject("ReaperDevices", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] ReaperProject { + get { + object obj = ResourceManager.GetObject("ReaperProject", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] ReaperTrack { + get { + object obj = ResourceManager.GetObject("ReaperTrack", resourceCulture); + return ((byte[])(obj)); + } + } + /// /// Looks up a localized resource of type System.Byte[]. /// diff --git a/WaveSabreConvert/Properties/Resources.resx b/WaveSabreConvert/Properties/Resources.resx index 775e2cba..e3f5c30d 100644 --- a/WaveSabreConvert/Properties/Resources.resx +++ b/WaveSabreConvert/Properties/Resources.resx @@ -118,6 +118,15 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\resources\reaperdevices.rpp;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\resources\reaperproject.rpp;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\resources\reapertrack.rpp;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\template.xrns;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/WaveSabreConvert/ReaperInject.cs b/WaveSabreConvert/ReaperInject.cs new file mode 100644 index 00000000..c482f37d --- /dev/null +++ b/WaveSabreConvert/ReaperInject.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace WaveSabreConvert +{ + public class ReaperInject + { + ILog logger; + private Dictionary _devices; + + public string InjectPatches(Song song, ILog logger) + { + this.logger = logger; + + CreateDevices(); + + var project = Encoding.UTF8.GetString(WaveSabreConvert.Properties.Resources.ReaperProject); + + var sb = new StringBuilder(); + + foreach (var track in song.Tracks) + { + if (track.Events.Count > 0) + { + logger.WriteLine(string.Format("Converting track: {0}", track.Name)); + sb.Append(CreateTrack(track)); + } + } + + project = project.Replace("~Tracks~", sb.ToString()); + + return project; + } + + private void CreateDevices() + { + _devices = new Dictionary(); + var devices = Encoding.UTF8.GetString(WaveSabreConvert.Properties.Resources.ReaperDevices); + using (StringReader reader = new StringReader(devices)) + { + var line = ""; + while (line != null) + { + line = reader.ReadLine(); + if (line != null && line.Contains(".dll")) + { + var sb = new StringBuilder(); + sb.AppendLine(line); + var items = SplitData(line); + line = reader.ReadLine(); + while (!line.Contains(">")) + { + sb.AppendLine(line); + line = reader.ReadLine(); + } + sb.AppendLine(line); + _devices.Add(items[2], sb.ToString()); + } + } + } + } + + private List SplitData(string data) + { + return Regex.Matches(data, @"[\""].+?[\""]|[^ ]+") + .Cast() + .Select(m => m.Value) + .ToList(); + } + + private string CreateTrack(Song.Track track) + { + var reaperTrack = Encoding.UTF8.GetString(WaveSabreConvert.Properties.Resources.ReaperTrack).Replace("~TrackName~", track.Name); + + var sb = new StringBuilder(); + foreach (var device in track.Devices) + { + sb.Append(CreateDevice(device)); + } + reaperTrack = reaperTrack.Replace("~Devices~", sb.ToString()); + + return reaperTrack; + } + + private string CreateDevice(Song.Device device) + { + var reaperDevice = ""; + var injected = ""; + + var deviceId = device.Id.ToString() + ".dll"; + + _devices.TryGetValue(deviceId, out reaperDevice); + + if (string.IsNullOrEmpty(reaperDevice)) + { + // Whoops + logger.WriteLine(string.Format("Device {0} not found", deviceId)); + } + else + { + injected = InjectDevice(reaperDevice, device.Chunk); + } + + return injected; + } + + private string InjectDevice(string reaperDevice, byte[] deviceChunk) + { + var chunkList = new List(); + + var header = ""; + var footer = ""; + + // compile all base64 strings to one bin chunk + using (var reader = new StringReader(reaperDevice)) + { + var line = reader.ReadLine(); + while (line != null) + { + line = line.TrimStart(); + if (line.StartsWith("<")) + { + header = line; + } + else if (line.StartsWith(">")) + { + footer = line; + } + else + { + chunkList.AddRange(Convert.FromBase64String(line).ToList()); + } + + line = reader.ReadLine(); + } + } + + var headerChunk = new BinaryWriter(new MemoryStream()); + var footerChunk = new BinaryWriter(new MemoryStream()); + + // vst chunk + using (var reader = new BinaryReader(new MemoryStream(chunkList.ToArray()))) + { + headerChunk.Write(reader.ReadChars(4)); + headerChunk.Write(reader.ReadInt32()); + var inputChannels = reader.ReadInt32(); + headerChunk.Write(inputChannels); + headerChunk.Write(reader.ReadBytes(inputChannels * 8)); + + var outputChannels = reader.ReadInt32(); + headerChunk.Write(outputChannels); + headerChunk.Write(reader.ReadBytes(outputChannels * 8)); + + var chunkLength = reader.ReadInt32(); + headerChunk.Write(deviceChunk.Length); + var val1 = reader.ReadInt32(); + var val2 = reader.ReadInt32(); + + headerChunk.Write(val1); + headerChunk.Write(val2); + + reader.ReadBytes(chunkLength); + int leftover = (int)reader.BaseStream.Length - (int)reader.BaseStream.Position; + footerChunk.Write(reader.ReadBytes(leftover)); + } + + var sb = new StringBuilder(); + var headerMs = (MemoryStream)headerChunk.BaseStream; + var footerMs = (MemoryStream)footerChunk.BaseStream; + var baseChunks = SplitInParts(Convert.ToBase64String(deviceChunk), 128); + + + sb.AppendLine(header); + sb.AppendLine(Convert.ToBase64String(headerMs.ToArray())); + foreach (var chunk in baseChunks) + { + sb.AppendLine(chunk); + } + sb.AppendLine(Convert.ToBase64String(footerMs.ToArray())); + sb.AppendLine(footer); + + return sb.ToString(); + + } + + private IEnumerable SplitInParts(string s, Int32 partLength) + { + if (s == null) + throw new ArgumentNullException("s"); + if (partLength <= 0) + throw new ArgumentException("Part length has to be positive.", "partLength"); + + for (var i = 0; i < s.Length; i += partLength) + yield return s.Substring(i, Math.Min(partLength, s.Length - i)); + } + } +} diff --git a/WaveSabreConvert/Resources/ReaperDevices.rpp b/WaveSabreConvert/Resources/ReaperDevices.rpp new file mode 100644 index 00000000..e33bc4dd --- /dev/null +++ b/WaveSabreConvert/Resources/ReaperDevices.rpp @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + diff --git a/WaveSabreConvert/Resources/ReaperProject.rpp b/WaveSabreConvert/Resources/ReaperProject.rpp new file mode 100644 index 00000000..85455945 --- /dev/null +++ b/WaveSabreConvert/Resources/ReaperProject.rpp @@ -0,0 +1,87 @@ + + + RENDER_FILE "" + RENDER_PATTERN "" + RENDER_FMT 0 2 0 + RENDER_1X 0 + RENDER_RANGE 1 0 0 18 1000 + RENDER_RESAMPLE 3 0 1 + RENDER_ADDTOPROJ 0 + RENDER_STEMS 0 + RENDER_DITHER 0 + TIMELOCKMODE 1 + TEMPOENVLOCKMODE 1 + ITEMMIX 0 + DEFPITCHMODE 589824 0 + TAKELANE 1 + SAMPLERATE 44100 0 0 + + LOCK 1 + + GLOBAL_AUTO -1 + TEMPO 120 4 4 + PLAYRATE 1 0 0.25 4 + SELECTION 0 1.5 + SELECTION2 0 1.5 + MASTERAUTOMODE 0 + MASTERTRACKHEIGHT 0 0 + MASTERPEAKCOL 16576 + MASTERMUTESOLO 0 + MASTERTRACKVIEW 0 0.6667 0.5 0.5 0 0 0 + MASTERHWOUT 0 0 1 0 0 0 0 -1 + MASTER_NCH 2 2 + MASTER_VOLUME 1 0 -1 -1 1 + MASTER_FX 1 + MASTER_SEL 0 + + + +~Tracks~ +> diff --git a/WaveSabreConvert/Resources/reapertrack.rpp b/WaveSabreConvert/Resources/reapertrack.rpp new file mode 100644 index 00000000..de9763a3 --- /dev/null +++ b/WaveSabreConvert/Resources/reapertrack.rpp @@ -0,0 +1,28 @@ + + > + diff --git a/WaveSabreConvert/WaveSabreConvert.csproj b/WaveSabreConvert/WaveSabreConvert.csproj index 896f263a..169c7ddb 100644 --- a/WaveSabreConvert/WaveSabreConvert.csproj +++ b/WaveSabreConvert/WaveSabreConvert.csproj @@ -47,6 +47,7 @@ + @@ -83,6 +84,9 @@ + + +