various feature additions, improvements, and bug fixes to synthesized audio plugins and editors

This commit is contained in:
Michael Becker 2020-05-14 23:47:24 -04:00
parent 51414cc4a7
commit f884365c95
No known key found for this signature in database
GPG Key ID: 506F54899E2BFED7
17 changed files with 774 additions and 109 deletions

View File

@ -129,24 +129,26 @@
</Items>
</Command>
<!-- Length : controls the quantize of length when drawing a new note -->
<Command ID="PianoRollEditor_ContextMenu_Length_4" Title="1/4 [480]" />
<Command ID="PianoRollEditor_ContextMenu_Length_8" Title="1/8 [240]" />
<Command ID="PianoRollEditor_ContextMenu_Length_16" Title="1/16 [120]" />
<Command ID="PianoRollEditor_ContextMenu_Length_32" Title="1/32 [60]" />
<Command ID="PianoRollEditor_ContextMenu_Length_64" Title="1/64 [30]" />
<Command ID="PianoRollEditor_ContextMenu_Length_Off" Title="Off" />
<Command ID="PianoRollEditor_ContextMenu_Length_Triplet" Title="Triplet" />
<Command ID="PianoRollEditor_ContextMenu_Length" Title="_Length">
<!-- NoteLength : controls the quantize of length when drawing a new note -->
<Command ID="PianoRollEditor_ContextMenu_NoteLength_4" Title="1/4 [480]" />
<Command ID="PianoRollEditor_ContextMenu_NoteLength_8" Title="1/8 [240]" />
<Command ID="PianoRollEditor_ContextMenu_NoteLength_16" Title="1/16 [120]" />
<Command ID="PianoRollEditor_ContextMenu_NoteLength_32" Title="1/32 [60]" />
<Command ID="PianoRollEditor_ContextMenu_NoteLength_64" Title="1/64 [30]" />
<Command ID="PianoRollEditor_ContextMenu_NoteLength_Off" Title="Off" />
<Command ID="PianoRollEditor_ContextMenu_NoteLength_Default" Title="Default" />
<Command ID="PianoRollEditor_ContextMenu_NoteLength_Triplet" Title="Triplet" />
<Command ID="PianoRollEditor_ContextMenu_NoteLength" Title="Note _Length">
<Items>
<CommandReference CommandID="PianoRollEditor_ContextMenu_Length_4" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_Length_8" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_Length_16" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_Length_32" /> <!-- default -->
<CommandReference CommandID="PianoRollEditor_ContextMenu_Length_64" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_Length_Off" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_NoteLength_4" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_NoteLength_8" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_NoteLength_16" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_NoteLength_32" /> <!-- default -->
<CommandReference CommandID="PianoRollEditor_ContextMenu_NoteLength_64" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_NoteLength_Off" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_NoteLength_Default" />
<Separator />
<CommandReference CommandID="PianoRollEditor_ContextMenu_Length_Triplet" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_NoteLength_Triplet" />
</Items>
</Command>
@ -215,9 +217,9 @@
<CommandReference CommandID="PianoRollEditor_ContextMenu_Scale" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_Chord" />
<Separator />
<CommandReference CommandID="PianoRollEditor_ContextMenu_NoteFixedLength" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_Quantize" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_Length" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_NoteLength" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_NoteFixedLength" />
<CommandReference CommandID="PianoRollEditor_ContextMenu_ShowGridLines" />
<Separator />
<CommandReference CommandID="EditUndo" />

View File

@ -3,24 +3,29 @@
<Associations>
<Association>
<Filters>
<Filter Title="VOCALOID2 voice sequence (MIDI)">
<Filter Title="VOCALOID5 project (JSON/ZIP)">
<FileNameFilters>
<FileNameFilter>*.vsq</FileNameFilter>
<FileNameFilter>*.vpr</FileNameFilter>
</FileNameFilters>
<MagicByteSequences>
<MagicByteSequence>
<MagicByte Type="String">PK</MagicByte>
</MagicByteSequence>
</MagicByteSequences>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.Multimedia.Audio.Synthesized.SynthesizedAudioObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.Plugins.Vocaloid.DataFormats.Multimedia.Audio.Synthesized.Vocaloid.VSQDataFormat" />
<DataFormat TypeName="UniversalEditor.Plugins.Vocaloid.DataFormats.Multimedia.Audio.Synthesized.Vocaloid.VPR.VPRProjectZIPDataFormat" />
</DataFormats>
</Association>
<Association>
<Filters>
<Filter Title="VOCALOID3 voice sequence (XML)">
<Filter Title="VOCALOID5 voice sequence (JSON)">
<FileNameFilters>
<FileNameFilter>*.vsqx</FileNameFilter>
<FileNameFilter>sequence.json</FileNameFilter>
</FileNameFilters>
</Filter>
</Filters>
@ -28,7 +33,7 @@
<ObjectModel TypeName="UniversalEditor.ObjectModels.Multimedia.Audio.Synthesized.SynthesizedAudioObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.Plugins.Vocaloid.DataFormats.Multimedia.Audio.Synthesized.Vocaloid.VSQXDataFormat" />
<DataFormat TypeName="UniversalEditor.Plugins.Vocaloid.DataFormats.Multimedia.Audio.Synthesized.Vocaloid.VPR.VPRSequenceJSONDataFormat" />
</DataFormats>
</Association>
</Associations>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<UniversalEditor Version="4.0">
<Associations>
<Association>
<Filters>
<Filter Title="VOCALOID2 voice sequence (MIDI)">
<FileNameFilters>
<FileNameFilter>*.vsq</FileNameFilter>
</FileNameFilters>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.Multimedia.Audio.Synthesized.SynthesizedAudioObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.Plugins.Vocaloid.DataFormats.Multimedia.Audio.Synthesized.Vocaloid.VSQDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<UniversalEditor Version="4.0">
<Associations>
<Association>
<Filters>
<Filter Title="VOCALOID3 voice sequence (XML)">
<FileNameFilters>
<FileNameFilter>*.vsqx</FileNameFilter>
</FileNameFilters>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.Multimedia.Audio.Synthesized.SynthesizedAudioObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.Plugins.Vocaloid.DataFormats.Multimedia.Audio.Synthesized.Vocaloid.VSQXDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -728,8 +728,10 @@
<Content Include="Editors\Database\DatabaseEditor.glade" />
<Content Include="Editors\Multimedia\Synthesized\Dialogs\NotePropertiesDialog.glade" />
<Content Include="Extensions\AudioWorkstation\Extensions\Vocaloid\Associations\Voicebank\Vocaloid.uexml" />
<Content Include="Extensions\AudioWorkstation\Extensions\Vocaloid\Associations\SynthesizedAudio\Vocaloid.uexml" />
<Content Include="Extensions\AudioWorkstation\Extensions\Vocaloid\Associations\SynthesizedAudio\VSQ.uexml" />
<Content Include="Extensions\AudioWorkstation\Extensions\Vocaloid\Associations\VoicebankIndex\Vocaloid.uexml" />
<Content Include="Extensions\AudioWorkstation\Extensions\Vocaloid\Associations\SynthesizedAudio\VSQX.uexml" />
<Content Include="Extensions\AudioWorkstation\Extensions\Vocaloid\Associations\SynthesizedAudio\VPR.uexml" />
</ItemGroup>
<ItemGroup>
<Content Include="Configuration\Application.upl" />

View File

@ -26,7 +26,7 @@ using UniversalEditor.UserInterface;
using UniversalEditor.ObjectModels.Multimedia.Audio.Synthesized;
using UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Controls;
using UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Views;
namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll
{

View File

@ -32,7 +32,16 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll
{
public override void UpdateSelections()
{
throw new NotImplementedException();
Selections.Clear();
if (PianoRoll.SelectedCommands.Count > 0)
{
PianoRollEditorSelection sel = new PianoRollEditorSelection(this, PianoRoll);
for (int i = 0; i < PianoRoll.SelectedCommands.Count; i++)
{
sel.Commands.Add(PianoRoll.SelectedCommands[i]);
}
Selections.Add(sel);
}
}
protected override EditorSelection CreateSelectionInternal(object content)
@ -40,6 +49,11 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll
throw new NotImplementedException();
}
protected override void OnDocumentEdited(EventArgs e)
{
base.OnDocumentEdited(e);
PianoRoll.Refresh();
}
protected override void OnObjectModelChanged(EventArgs e)
{
base.OnObjectModelChanged(e);

View File

@ -0,0 +1,29 @@
//
// QuantizationMode.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll
{
public enum QuantizationMode
{
Length,
Position
}
}

View File

@ -21,6 +21,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MBS.Framework.Drawing;
using MBS.Framework.UserInterface;
@ -34,7 +35,7 @@ using UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Dialogs;
using UniversalEditor.ObjectModels.Multimedia.Audio.Synthesized;
using UniversalEditor.UserInterface;
namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Controls
namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Views
{
/// <summary>
/// Provides a UWT-based <see cref="View" /> for manipulating <see cref="SynthesizedAudioCommand" />s in a piano roll style.
@ -60,6 +61,23 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_Draw", ContextMenuPencil_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_Erase", ContextMenuErase_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_Quantize_4", ContextMenu_Quantize_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_Quantize_8", ContextMenu_Quantize_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_Quantize_16", ContextMenu_Quantize_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_Quantize_32", ContextMenu_Quantize_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_Quantize_64", ContextMenu_Quantize_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_Quantize_Off", ContextMenu_Quantize_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_Quantize_Triplet", ContextMenu_Quantize_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_NoteLength_4", ContextMenu_NoteLength_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_NoteLength_8", ContextMenu_NoteLength_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_NoteLength_16", ContextMenu_NoteLength_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_NoteLength_32", ContextMenu_NoteLength_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_NoteLength_64", ContextMenu_NoteLength_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_NoteLength_Off", ContextMenu_NoteLength_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_NoteLength_Default", ContextMenu_NoteLength_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_NoteLength_Triplet", ContextMenu_NoteLength_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_NoteFixedLength_1", ContextMenu_NoteFixedLength_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_NoteFixedLength_2", ContextMenu_NoteFixedLength_Click);
Application.AttachCommandEventHandler("PianoRollEditor_ContextMenu_NoteFixedLength_4", ContextMenu_NoteFixedLength_Click);
@ -152,17 +170,6 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
/// <value>The length of a newly-created note.</value>
public int FixedNoteLength { get; set; } = -1;
private int _PositionQuantization = -1;
public int PositionQuantization
{
get { return _PositionQuantization; }
set
{
_PositionQuantization = value;
Refresh();
}
}
private void ContextMenu_NoteFixedLength_Click(object sender, EventArgs e)
{
Command cmd = (sender as Command);
@ -190,6 +197,65 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
}
}
}
private void ContextMenu_Quantize_Click(object sender, EventArgs e)
{
Command cmd = (sender as Command);
string sValue = cmd.ID.Substring("PianoRollEditor_ContextMenu_Quantize_".Length);
int iValue = 4; //-1;
switch (sValue)
{
case "Off":
{
break;
}
case "Triplet":
{
break;
}
case "Dot":
{
break;
}
default:
{
iValue = Int32.Parse(sValue);
break;
}
}
PositionQuantization = (int)((double)1920 / iValue);
}
private void ContextMenu_NoteLength_Click(object sender, EventArgs e)
{
Command cmd = (sender as Command);
string sValue = cmd.ID.Substring("PianoRollEditor_ContextMenu_NoteLength_".Length);
int iValue = 4; //-1;
switch (sValue)
{
case "Off":
{
break;
}
case "Triplet":
{
break;
}
case "Default":
{
iValue = -1;
break;
}
default:
{
iValue = Int32.Parse(sValue);
break;
}
}
LengthQuantization = (int)((double)1920 / iValue);
}
// TODO: make this more user-friendly
private static Dictionary<string, int[]> Scales = new Dictionary<string, int[]>();
@ -317,7 +383,6 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
set { _SelectedTrack = value; Refresh(); }
}
public int GridSize { get; set; } = 4;
public Dimension2D NoteSize { get; set; } = new Dimension2D(12, 16);
private Pen pGrid = new Pen(Colors.LightGray);
@ -327,20 +392,54 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
private SolidBrush bSelectionFillDrawing = new SolidBrush(Color.FromRGBADouble(Colors.DarkGray.R, Colors.DarkGray.G, Colors.DarkGray.B, 0.5));
private bool mvarShowKeyboard = true;
/// <summary>
/// Gets or sets a value indicating whether the virtual keyboard should be shown on this <see cref="PianoRollView" />.
/// </summary>
/// <value><c>true</c> if the virtual keyboard should be shown; otherwise, <c>false</c>.</value>
public bool ShowKeyboard { get { return mvarShowKeyboard; } set { mvarShowKeyboard = value; Invalidate(); } }
private int mvarKeyboardWidth = 64;
public int KeyboardWidth { get { return mvarKeyboardWidth; } set { mvarKeyboardWidth = value; Invalidate(); } }
private int mvarQuarterNoteWidth = 48;
private int mvarNoteHeight = 22;
private int _LengthQuantization = -1;
/// <summary>
/// Gets or sets the quantization for note length (i.e., the width of a quarter note on the grid). All quantization operations are relative to this value.
/// </summary>
/// <value>The quantization for note length (i.e., the width of a quarter note on the grid).</value>
public int LengthQuantization { get { return _LengthQuantization; } set { _LengthQuantization = value; Invalidate(); } }
/// <summary>
/// Gets or sets the quantization for note positioning.
/// </summary>
/// <value>The quantization for note positioning.</value>
public int PositionQuantization { get; set; } = 60;
private int GetLengthQuantization()
{
if (LengthQuantization == -1)
return PositionQuantization;
return LengthQuantization;
}
private int _GridWidth = 120;
public int GridWidth { get { return _GridWidth; }set { _GridWidth = value; Invalidate(); } }
private int _NoteHeight = 22;
/// <summary>
/// Gets or sets the height of a note on the grid.
/// </summary>
/// <value>The height of a note on the grid.</value>
public int NoteHeight { get { return _NoteHeight; } set { _NoteHeight = value; Invalidate(); } }
private bool _HighlightOverlappingNotes = true;
/// <summary>
/// Gets or sets a value indicating whether overlapping notes on this <see cref="PianoRollView" /> grid are highlighted.
/// </summary>
/// <value><c>true</c> if overlapping notes should be highlighted; otherwise, <c>false</c>.</value>
public bool HighlightOverlappingNotes { get { return _HighlightOverlappingNotes; } set { _HighlightOverlappingNotes = value; Invalidate(); } }
private double mvarZoomFactor = 1.0;
public double ZoomFactor { get { return mvarZoomFactor; } set { mvarZoomFactor = value; Invalidate(); } }
private Dimension2D mvarQuantizationSize = new Dimension2D(16, 16);
public Dimension2D QuantizationSize { get { return mvarQuantizationSize; } set { mvarQuantizationSize = value; Invalidate(); } }
private bool m_selecting = false;
private double cx = 0, cy = 0;
private double dx = 0, dy = 0;
@ -356,6 +455,7 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
Focus();
if (SelectedTrack == null) return;
@ -411,10 +511,10 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
dy = e.Y;
m_selecting = true;
drag_OriginalLocation = Quantize(new Vector2D(cx, cy));
drag_OriginalLocation = Quantize(new Vector2D(cx, cy), QuantizationMode.Position);
if (cmd is SynthesizedAudioCommandNote)
{
note_OriginalLocation = Quantize(GetNoteRect(cmd as SynthesizedAudioCommandNote).Location);
note_OriginalLocation = Quantize(GetNoteRect(cmd as SynthesizedAudioCommandNote).Location, QuantizationMode.Position);
}
drag_CurrentLocation = drag_OriginalLocation;
}
@ -447,7 +547,7 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
if (draggingCommand == null && (SelectionMode == PianoRollSelectionMode.Select || SelectionMode == PianoRollSelectionMode.Insert))
{
drag_CurrentLocation = Quantize(new Vector2D(dx, drag_OriginalLocation.Y));
drag_CurrentLocation = Quantize(new Vector2D(dx, drag_OriginalLocation.Y), QuantizationMode.Length);
if (SelectionMode == PianoRollSelectionMode.Select)
{
Rectangle rectSelection = new Rectangle(cx, cy, dx - cx, dy - cy);
@ -462,7 +562,7 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
}
else
{
drag_CurrentLocation = Quantize(new Vector2D(dx, dy));
drag_CurrentLocation = Quantize(new Vector2D(dx, dy), QuantizationMode.Length);
}
Refresh();
}
@ -497,11 +597,21 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
double y = drag_CurrentLocation.Y - drag_OriginalLocation.Y;
Rectangle origNoteRect = GetNoteRect(note);
Vector2D v = Quantize(origNoteRect.Location);
Vector2D v = Quantize(origNoteRect.Location, QuantizationMode.Position);
v.X += x;
v.Y += y;
ApplyNoteRect(ref note, v);
if ((e.ModifierKeys & KeyboardModifierKey.Control) == KeyboardModifierKey.Control)
{
// copy the note to the current location
SynthesizedAudioCommandNote note2 = note.Clone() as SynthesizedAudioCommandNote;
ApplyNoteRect(ref note2, v);
SelectedTrack.Commands.Add(note2);
}
else
{
ApplyNoteRect(ref note, v);
}
}
}
@ -526,8 +636,8 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
SynthesizedAudioCommandNote note = new SynthesizedAudioCommandNote();
note.Position = (int)drag_OriginalLocation.X;
note.Length = (drag_CurrentLocation.X - drag_OriginalLocation.X);
note.Position = LocationToNotePosition((int)drag_OriginalLocation.X, QuantizationMode.Position) * 4;
note.Length = LocationToNotePosition((int)(drag_CurrentLocation.X - drag_OriginalLocation.X), QuantizationMode.Length) * 4;
note.Frequency = ValueToFrequency((int)drag_OriginalLocation.Y);
Editor.BeginEdit();
@ -547,9 +657,18 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
}
}
private int LocationToNotePosition(int x, QuantizationMode mode)
{
return (int)Unquantize(new MBS.Framework.Drawing.Vector2D(x, 0), mode).X;
}
private int NotePositionToLocation(double x)
{
return (int)(x / 4);
}
private void ApplyNoteRect(ref SynthesizedAudioCommandNote note, Vector2D quantized)
{
note.Position = (int)quantized.X;
note.Position = LocationToNotePosition((int)quantized.X, QuantizationMode.Position) * 4;
note.Frequency = ValueToFrequency((int)quantized.Y);
}
@ -625,19 +744,31 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
"A#", "A", "G#", "G", "F#", "F", "E", "D#", "D", "C#", "C", "B"
};
private Vector2D Quantize(Vector2D pt)
private Vector2D Quantize(Vector2D pt, QuantizationMode mode)
{
if (mvarShowKeyboard)
pt.X -= mvarKeyboardWidth;
int qX = (int)((double)(pt.X / mvarQuarterNoteWidth));
int qY = (int)((double)((pt.Y / mvarNoteHeight)));
int quant;
if (mode == QuantizationMode.Length)
quant = GetLengthQuantization();
else
quant = PositionQuantization;
int qX = (int)((double)(pt.X / (quant * ZoomFactor)));
int qY = (int)((double)((pt.Y / NoteHeight)));
return new Vector2D(qX, qY);
}
private Vector2D Unquantize(Vector2D pt)
private Vector2D Unquantize(Vector2D pt, QuantizationMode mode)
{
int uqX = (int)(pt.X * mvarQuarterNoteWidth);
int uqY = (int)(pt.Y * mvarNoteHeight);
int quant;
if (mode == QuantizationMode.Length)
quant = GetLengthQuantization();
else
quant = PositionQuantization;
int uqX = (int)(pt.X * (quant * ZoomFactor));
int uqY = (int)(pt.Y * NoteHeight);
return new Vector2D(uqX, uqY);
}
@ -668,26 +799,46 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
private Rectangle GetNoteRect(SynthesizedAudioCommandNote note)
{
Rectangle gridRect = GetGridRect();
Vector2D pt1 = Unquantize(new Vector2D((int)(note.Position), FrequencyToValue(note.Frequency)));
Vector2D pt2 = Unquantize(new Vector2D((int)note.Length, FrequencyToValue(note.Frequency)));
return new Rectangle(gridRect.X + pt1.X + 1, gridRect.Y + pt1.Y + 1, pt2.X - 1, mvarNoteHeight - 1);
int x = (int)NotePositionToLocation(note.Position);
int y = FrequencyToValue(note.Frequency);
int width = (int)NotePositionToLocation((int)note.Length);
int height = NoteHeight;
return new Rectangle(gridRect.X + x + 1, gridRect.Y + y + 1, width - 1, height - 1);
}
private double ValueToFrequency(int value)
{
return value;
return (81 - value);
}
private int FrequencyToValue(double frequency)
{
return (int)frequency;
return (int)((81 - frequency) * NoteHeight);
}
private bool _scrollBoundsChanged = true;
private void RecalcScrollBounds()
{
for (int i = 0; i < SelectedTrack.Commands.Count; i++)
{
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
int gridWidth = (int)(mvarQuarterNoteWidth * mvarZoomFactor);
int gridHeight = (int)(mvarNoteHeight * mvarZoomFactor);
int gridWidth = (int)(GridWidth * mvarZoomFactor);
int gridHeight = (int)(NoteHeight * mvarZoomFactor);
if (_scrollBoundsChanged)
{
RecalcScrollBounds();
_scrollBoundsChanged = false;
}
Rectangle gridRect = GetGridRect();
if (mvarShowKeyboard)
@ -738,7 +889,7 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
}
for (int i = 0; i < Size.Width; i += (ShowGridLines ? (gridWidth / 2) : gridWidth))
{
if ((i % (mvarQuarterNoteWidth * 4)) == 0)
if ((i % GetLengthQuantization()) == 0)
{
gridPen.Color = Colors.Gray.Alpha(0.50);
}
@ -758,24 +909,10 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
SynthesizedAudioCommandNote note = (cmd as SynthesizedAudioCommandNote);
Rectangle rect = GetNoteRect(note);
if (mvarSelectedCommands.Contains(cmd))
{
e.Graphics.FillRectangle(new SolidBrush(SystemColors.HighlightBackground), rect);
}
else
{
e.Graphics.FillRectangle(new SolidBrush(SystemColors.WindowBackground), rect);
e.Graphics.FillRectangle(new SolidBrush(Colors.Green.Alpha(0.3)), rect);
}
e.Graphics.DrawRectangle(new Pen(Colors.Green.Alpha(0.5)), rect);
Rectangle textRect = new Rectangle(rect.X + 2, rect.Y + 10, rect.Width - 4, rect.Height - 2);
if (!(txt.Visible && _EditingNote == cmd))
{
e.Graphics.DrawText(String.Format("{0} [ {1} ]", note.Lyric, note.Phoneme), Font, textRect, new SolidBrush(mvarSelectedCommands.Contains(cmd) ? SystemColors.HighlightForeground : SystemColors.WindowForeground));
}
bool overlaps = false;
if (HighlightOverlappingNotes) overlaps = NoteOverlaps(note);
if (!DrawNote(e.Graphics, rect, note.Lyric, note.Phoneme, mvarSelectedCommands.Contains(cmd), _EditingNote == note, overlaps))
break;
}
}
}
@ -786,7 +923,7 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
{
Rectangle origNoteRect = GetNoteRect(draggingCommand as SynthesizedAudioCommandNote);
Rectangle newNoteRect = GetNoteRect(draggingCommand as SynthesizedAudioCommandNote);
newNoteRect.Location = Unquantize(new Vector2D(note_OriginalLocation.X + (drag_CurrentLocation.X - drag_OriginalLocation.X), note_OriginalLocation.Y + (drag_CurrentLocation.Y - drag_OriginalLocation.Y)));
newNoteRect.Location = Unquantize(new Vector2D(note_OriginalLocation.X + (drag_CurrentLocation.X - drag_OriginalLocation.X), note_OriginalLocation.Y + (drag_CurrentLocation.Y - drag_OriginalLocation.Y)), QuantizationMode.Position);
Vector2D diff = new Vector2D(newNoteRect.X - origNoteRect.X, newNoteRect.Y - origNoteRect.Y);
foreach (SynthesizedAudioCommand cmd in mvarSelectedCommands)
@ -812,7 +949,7 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
}
else if (SelectionMode == PianoRollSelectionMode.Insert)
{
Rectangle dragrect = new Rectangle(drag_OriginalLocation.X * mvarQuarterNoteWidth, drag_OriginalLocation.Y * mvarNoteHeight, (drag_CurrentLocation.X * mvarQuarterNoteWidth) - (drag_OriginalLocation.X * mvarQuarterNoteWidth), mvarNoteHeight);
Rectangle dragrect = new Rectangle(drag_OriginalLocation.X * PositionQuantization, drag_OriginalLocation.Y * NoteHeight, (drag_CurrentLocation.X * GetLengthQuantization()) - (drag_OriginalLocation.X * GetLengthQuantization()), NoteHeight);
if (mvarShowKeyboard)
{
dragrect.X += mvarKeyboardWidth;
@ -837,11 +974,58 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
}
*/
}
private bool NoteOverlaps(SynthesizedAudioCommandNote note)
{
Rectangle rect = GetNoteRect(note);
for (int i = 0; i < SelectedTrack.Commands.Count; i++)
{
SynthesizedAudioCommandNote note2 = SelectedTrack.Commands[i] as SynthesizedAudioCommandNote;
if (note2 == null) continue;
if (note2 == note) continue;
Rectangle rect2 = GetNoteRect(note2);
if ((rect.X >= rect2.X && rect.X <= rect2.Right) || (rect2.X >= rect.X & rect2.X <= rect.Right))
return true;
}
return false;
}
private bool DrawNote(Graphics graphics, Rectangle rect, string lyric, string phoneme, bool selected, bool editing, bool overlaps)
{
if (rect.X > Size.Width)
return false; // no need to continue since we've reached the end of the visible area
Color noteColor = SystemColors.HighlightBackground.Darken(0.1);
if (overlaps)
{
noteColor = Colors.DarkGray;
}
if (selected)
{
graphics.FillRectangle(new SolidBrush(SystemColors.HighlightBackground), rect);
}
else
{
graphics.FillRectangle(new SolidBrush(SystemColors.WindowBackground), rect);
graphics.FillRectangle(new SolidBrush(noteColor.Alpha(0.3)), rect);
}
graphics.DrawRectangle(new Pen(noteColor.Alpha(0.5)), rect);
Rectangle textRect = new Rectangle(rect.X + 2, rect.Y + 10, rect.Width - 4, rect.Height - 2);
if (!(txt.Visible && editing))
{
graphics.DrawText(String.Format("{0} [ {1} ]", lyric, phoneme), Font, textRect, new SolidBrush(selected ? SystemColors.HighlightForeground : SystemColors.WindowForeground));
}
return true;
}
private void DrawKeyboard(Graphics g)
{
int gridWidth = (int)(mvarQuarterNoteWidth * mvarZoomFactor);
int gridHeight = (int)(mvarNoteHeight * mvarZoomFactor);
int gridWidth = (int)(GetLengthQuantization() * mvarZoomFactor);
int gridHeight = (int)(NoteHeight * mvarZoomFactor);
Rectangle keyboardRect = GetKeyboardRect();
for (int i = 0; i < keyboardRect.Height; i += gridHeight)
@ -864,11 +1048,11 @@ namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll.Control
private int QuantizeHeight(int cy)
{
return (int)((double)cy / mvarNoteHeight);
return (int)((double)cy / NoteHeight);
}
private int QuantizeWidth(int cy)
{
return (int)((double)cy / mvarQuarterNoteWidth);
return (int)((double)cy / GetLengthQuantization());
}
}
}

View File

@ -0,0 +1,49 @@
//
// PianoRollEditorSelection.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using UniversalEditor.Editors.Multimedia.Audio.Synthesized.PianoRoll;
using UniversalEditor.ObjectModels.Multimedia.Audio.Synthesized;
using UniversalEditor.UserInterface;
namespace UniversalEditor.Editors.Multimedia.Audio.Synthesized
{
public class PianoRollEditorSelection : EditorSelection
{
private PianoRoll.Views.PianoRollView _parent = null;
internal PianoRollEditorSelection(Editor editor, PianoRoll.Views.PianoRollView parent) : base(editor)
{
_parent = parent;
}
public SynthesizedAudioCommand.SynthesizedAudioCommandCollection Commands { get; private set; } = new SynthesizedAudioCommand.SynthesizedAudioCommandCollection();
public override object Content { get => Commands; set => Commands = (SynthesizedAudioCommand.SynthesizedAudioCommandCollection)value; }
protected override void DeleteInternal()
{
_parent.Editor.BeginEdit();
for (int i = 0; i < Commands.Count; i++)
{
_parent.SelectedTrack.Commands.Remove(Commands[i]);
}
_parent.Editor.EndEdit();
}
}
}

View File

@ -48,6 +48,8 @@
<Compile Include="Editors\Multimedia\Palette\PaletteEntrySelection.cs" />
<Compile Include="Editors\Multimedia\Audio\Voicebank\VoicebankEditor.cs" />
<Compile Include="Editors\Multimedia\PictureCollection\PictureCollectionEditor.cs" />
<Compile Include="Editors\Multimedia\Audio\Synthesized\PianoRoll\QuantizationMode.cs" />
<Compile Include="Editors\Multimedia\Audio\Synthesized\PianoRollEditorSelection.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Editors\" />

View File

@ -72,27 +72,27 @@ namespace UniversalEditor.DataFormats.Multimedia.Audio.Synthesized.UTAU
InitializePhonemeDictionary();
}
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
DataFormatReference dfr = base.MakeReferenceInternal();
dfr.Clear();
dfr.Capabilities.Add(typeof(PropertyListObjectModel), DataFormatCapabilities.Bootstrap);
dfr.Capabilities.Add(typeof(SynthesizedAudioObjectModel), DataFormatCapabilities.All);
return dfr;
if (_dfr == null)
{
_dfr = base.MakeReferenceInternal();
_dfr.Capabilities.Add(typeof(SynthesizedAudioObjectModel), DataFormatCapabilities.All);
}
return _dfr;
}
protected override void BeforeLoadInternal(Stack<ObjectModel> objectModels)
{
base.BeforeLoadInternal(objectModels);
// base.Accessor.DefaultEncoding = IO.Encoding.GetRuntimeEncoding(System.Text.Encoding.GetEncoding("shift-jis"));
throw new NotImplementedException();
base.Accessor.DefaultEncoding = IO.Encoding.ShiftJIS;
objectModels.Push(new PropertyListObjectModel());
}
protected override void AfterLoadInternal(Stack<ObjectModel> objectModels)
{
base.AfterLoadInternal(objectModels);
PropertyListObjectModel plom = objectModels.Pop() as PropertyListObjectModel;
SynthesizedAudioObjectModel sa = objectModels.Pop() as SynthesizedAudioObjectModel;
@ -105,6 +105,8 @@ namespace UniversalEditor.DataFormats.Multimedia.Audio.Synthesized.UTAU
{
SynthesizedAudioTrack track = new SynthesizedAudioTrack();
Group grp = plom.Items[groupStart] as Group;
int position = 0;
while (grp.Name != "#TRACKEND")
{
SynthesizedAudioCommandNote note = null;
@ -116,6 +118,7 @@ namespace UniversalEditor.DataFormats.Multimedia.Audio.Synthesized.UTAU
{
note = new SynthesizedAudioCommandNote();
}
note.Position = position;
note.Length = int.Parse(grp.Items.OfType<Property>("Length").Value.ToString());
note.Lyric = grp.Items.OfType<Property>("Lyric").Value.ToString();
note.Phoneme = LyricToPhoneme(note.Lyric);
@ -126,25 +129,82 @@ namespace UniversalEditor.DataFormats.Multimedia.Audio.Synthesized.UTAU
note.Intensity = grp.GetPropertyValue<int>("Intensity");
note.Modulation = grp.GetPropertyValue<int>("Moduration");
note.PBType = grp.GetPropertyValue<int>("PBType");
note.Pitches = grp.GetPropertyValue<string>("Pitches").Split<double>(new char[] { ',' });
note.Envelope = grp.GetPropertyValue<string>("Envelope").Split(new char[] { ',' });
note.VBR = grp.GetPropertyValue<string>("VBR").Split<double>(new char[] { ',' });
note.Pitches = grp.GetPropertyValue<string>("Pitches", String.Empty).Split<double>(new char[] { ',' });
note.Envelope = grp.GetPropertyValue<string>("Envelope", String.Empty).Split(new char[] { ',' });
note.VBR = grp.GetPropertyValue<string>("VBR", String.Empty).Split<double>(new char[] { ',' });
track.Commands.Add(note);
groupStart++;
grp = plom.Items[groupStart] as Group;
position += (int)note.Length;
}
sa.Tracks.Add(track);
}
}
protected override void BeforeSaveInternal(Stack<ObjectModel> objectModels)
{
base.BeforeSaveInternal(objectModels);
SynthesizedAudioObjectModel sa = objectModels.Pop() as SynthesizedAudioObjectModel;
PropertyListObjectModel plom = new PropertyListObjectModel();
plom.Items.Add(new Group("#SETTING", new PropertyListItem[]
{
new Property("Tempo", sa.Tempo),
new Property("Tracks", sa.Tracks.Count.ToString()),
new Property("ProjectName", sa.Name),
new Property("VoiceDir", "%VOICE%"),
new Property("OutFile", System.IO.Path.ChangeExtension(System.IO.Path.GetFileName(Accessor.GetFileName()), ".wav")),
new Property("CacheDir", ".cache"),
new Property("Tool1", "wavtool.exe"),
new Property("Tool2", "resampler.exe"),
new Property("Mode2", true),
new Property("Flags", "g8BRE10H10")
}));
for (int i = 0; i < sa.Tracks.Count; i++)
{
for (int k = 0; k < sa.Tracks[i].Commands.Count; k++)
{
if (sa.Tracks[i].Commands[k] is SynthesizedAudioCommandNote)
{
SynthesizedAudioCommandNote note = sa.Tracks[i].Commands[k] as SynthesizedAudioCommandNote;
Group gNote = new Group(String.Format("#{0}", i.ToString().PadLeft(4, '0')), new PropertyListItem[]
{
new Property("Length", note.Length),
new Property("Lyric", note.Lyric),
new Property("NoteNum", note.Frequency),
new Property("PreUtterance", note.PreUtterance),
new Property("VoiceOverlap", note.VoiceOverlap),
new Property("Intensity", note.Intensity),
new Property("Moduration", note.Modulation),
new Property("Envelope", String.Join(",", note.Envelope))
});
plom.Items.Add(gNote);
}
}
plom.Items.Add(new Group("#TRACKEND"));
}
objectModels.Push(plom);
}
private string LyricToPhoneme(string lyric)
{
// Use PhonemeDictionary.xml lookup table to find the phoneme that corresponds to the
// lyric
Phoneme p = mvarPhonemeDictionary.PhonemeLists[0].GetPhonemeFromMapping(lyric);
if (p == null) return null;
return p.Value;
if (mvarPhonemeDictionary.PhonemeLists.Count > 0)
{
for (int i = 0; i < mvarPhonemeDictionary.PhonemeLists.Count; i++)
{
Phoneme p = mvarPhonemeDictionary.PhonemeLists[i].GetPhonemeFromMapping(lyric);
if (p != null) return p.Value;
}
}
return null;
}
}
}

View File

@ -66,6 +66,7 @@ namespace UniversalEditor.ObjectModels.Multimedia.Audio.Synthesized
PortamentoRising = this.PortamentoRising,
PreUtterance = this.PreUtterance,
Protected = this.Protected,
Position = this.Position,
Frequency = this.Frequency,
VBR = this.VBR.Clone() as double[],
VoiceOverlap = this.VoiceOverlap

View File

@ -0,0 +1,96 @@
//
// VPRProjectZIPDataFormat.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System.Collections.Generic;
using UniversalEditor.Accessors;
using UniversalEditor.DataFormats.FileSystem.ZIP;
using UniversalEditor.ObjectModels.FileSystem;
using UniversalEditor.ObjectModels.Multimedia.Audio.Synthesized;
namespace UniversalEditor.Plugins.Vocaloid.DataFormats.Multimedia.Audio.Synthesized.Vocaloid.VPR
{
public class VPRProjectZIPDataFormat : ZIPDataFormat
{
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
if (_dfr == null)
{
_dfr = base.MakeReferenceInternal();
_dfr.Capabilities.Add(typeof(SynthesizedAudioObjectModel), DataFormatCapabilities.All);
}
return _dfr;
}
protected override void BeforeLoadInternal(Stack<ObjectModel> objectModels)
{
base.BeforeLoadInternal(objectModels);
objectModels.Push(new FileSystemObjectModel());
}
protected override void AfterLoadInternal(Stack<ObjectModel> objectModels)
{
base.AfterLoadInternal(objectModels);
FileSystemObjectModel fsom = (objectModels.Pop() as FileSystemObjectModel);
ObjectModel whatever = objectModels.Pop();
if (whatever is SynthesizedAudioObjectModel)
{
// have the VPRSequenceJSONDataFormat load the sequence.json into the synthesized audio object model
SynthesizedAudioObjectModel vsq = (whatever as SynthesizedAudioObjectModel);
VPRSequenceJSONDataFormat vpr = new VPRSequenceJSONDataFormat();
File sequence_json = fsom.FindFile("Project\\sequence.json");
if (sequence_json == null) throw new InvalidDataFormatException("archive does not contain a file called 'Project\\sequence.json'");
MemoryAccessor ma = new MemoryAccessor(sequence_json.GetData());
Document.Load(vsq, vpr, ma);
}
else
{
// huh?
}
}
protected override void BeforeSaveInternal(Stack<ObjectModel> objectModels)
{
base.BeforeSaveInternal(objectModels);
ObjectModel whatever = objectModels.Pop();
FileSystemObjectModel fsom = new FileSystemObjectModel();
if (whatever is SynthesizedAudioObjectModel)
{
// have the VPRSequenceJSONDataFormat save the sequence.json and just add it as the only file in the ZIP
SynthesizedAudioObjectModel vsq = (whatever as SynthesizedAudioObjectModel);
VPRSequenceJSONDataFormat vpr = new VPRSequenceJSONDataFormat();
MemoryAccessor ma = new MemoryAccessor();
Document.Save(vsq, vpr, ma);
fsom.Files.Add("Project\\sequence.json", ma.ToArray());
}
else
{
// huh?
}
objectModels.Push(fsom);
}
}
}

View File

@ -0,0 +1,173 @@
//
// VPRSequenceJSONDataFormat.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using UniversalEditor.DataFormats.PropertyList.JavaScriptObjectNotation;
using UniversalEditor.ObjectModels.Multimedia.Audio.Synthesized;
using UniversalEditor.ObjectModels.PropertyList;
namespace UniversalEditor.Plugins.Vocaloid.DataFormats.Multimedia.Audio.Synthesized.Vocaloid
{
public class VPRSequenceJSONDataFormat : JSONDataFormat
{
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
if (_dfr == null)
{
_dfr = base.MakeReferenceInternal();
_dfr.Capabilities.Add(typeof(SynthesizedAudioObjectModel), DataFormatCapabilities.All);
}
return _dfr;
}
[CustomOptionText("Vendor", "Yamaha Corporation")]
public string Vendor { get; set; } = "Yamaha Corporation";
protected override void BeforeLoadInternal(Stack<ObjectModel> objectModels)
{
base.BeforeLoadInternal(objectModels);
objectModels.Push(new PropertyListObjectModel());
}
protected override void AfterLoadInternal(Stack<ObjectModel> objectModels)
{
base.AfterLoadInternal(objectModels);
PropertyListObjectModel plom = (objectModels.Pop() as PropertyListObjectModel);
SynthesizedAudioObjectModel vsq = (objectModels.Pop() as SynthesizedAudioObjectModel);
Group g = (plom.Items[0] as Group);
Group gVersion = g.Items.OfType<Group>("version");
Property pTracks = g.Items.OfType<Property>("tracks");
Group[] gTracks = pTracks.Value as Group[];
if (gTracks == null) throw new InvalidDataFormatException("tracks is not a Group[]");
for (int i = 0; i < gTracks.Length; i++)
{
SynthesizedAudioTrack track = new SynthesizedAudioTrack();
Property pParts = gTracks[i].Items.OfType<Property>("parts");
Group[] gParts = pParts.Value as Group[];
if (gParts == null) throw new InvalidDataFormatException("parts is not a Group[]");
for (int j = 0; j < gParts.Length; j++)
{
Property pNotes = gParts[j].Items.OfType<Property>("notes");
Group[] gNotes = pNotes.Value as Group[];
if (gNotes == null) throw new InvalidDataFormatException("notes is not a Group[]");
for (int k = 0; k < gNotes.Length; k++)
{
SynthesizedAudioCommandNote note = new SynthesizedAudioCommandNote();
Property pLyric = gNotes[k].Items.OfType<Property>("lyric");
Property pPhoneme = gNotes[k].Items.OfType<Property>("phoneme");
Property pIsProtected = gNotes[k].Items.OfType<Property>("isProtected");
Property pPos = gNotes[k].Items.OfType<Property>("pos");
Property pDuration = gNotes[k].Items.OfType<Property>("duration");
Property pNumber = gNotes[k].Items.OfType<Property>("number");
Property pVelocity = gNotes[k].Items.OfType<Property>("velocity");
Group gExp = gNotes[k].Items.OfType<Group>("exp");
Property pExpOpening = gExp.Items.OfType<Property>("opening");
Group dvqm = gNotes[k].Items.OfType<Group>("dvqm");
Group dvqmRelease = dvqm.Items.OfType<Group>("release");
Property dvqmReleaseCompID = dvqmRelease.Items.OfType<Property>("compID");
Group gVibrato = gNotes[k].Items.OfType<Group>("vibrato");
Property pVibratoType = gVibrato.Items.OfType<Property>("type");
Property pVibratoDuration = gVibrato.Items.OfType<Property>("duration");
track.Commands.Add(note);
}
}
vsq.Tracks.Add(track);
}
}
protected override void BeforeSaveInternal(Stack<ObjectModel> objectModels)
{
base.BeforeSaveInternal(objectModels);
SynthesizedAudioObjectModel vsq = (objectModels.Pop() as SynthesizedAudioObjectModel);
PropertyListObjectModel plom = new PropertyListObjectModel();
plom.Items.AddRange(new PropertyListItem[]
{
new Group("version", new PropertyListItem[]
{
new Property("major", 5),
new Property("minor", 0),
new Property("revision", 0)
}),
new Property("vender", Vendor),
new Property("title", vsq.Information.SongTitle),
new Group("masterTrack", new PropertyListItem[]
{
new Property("samplingRate", 44100),
new Group("loop", new PropertyListItem[]
{
new Property("isEnabled", false),
new Property("begin", 0),
new Property("end", 0)
})
}),
new Property("voices", new Group[]
{
new Group("", new PropertyListItem[]
{
new Property("compID", "BCNFCY43LB2LZCD4"),
new Property("name", "MIKU_V4X_Original_EVEC")
})
}),
new Property("tracks", new Group[]
{
new Group("", new PropertyListItem[]
{
new Property("type", 0),
new Property("name", "MIKU_V4X_ORIGINAL_EVEC"),
new Property("color", 0),
new Property("busNo", 0),
new Property("isFolded", false),
new Property("height", 0.0),
new Group("volume", new PropertyListItem[]
{
new Property("isFolded", true),
new Property("height", 0.0),
new Property("events", new Group[]
{
new Group("", new PropertyListItem[]
{
new Property("pos" , 0.0),
new Property("value", 0.0)
})
})
})
})
})
});
objectModels.Push(plom);
}
}
}

View File

@ -45,7 +45,7 @@ namespace UniversalEditor.Plugins.Vocaloid.DataFormats.Multimedia.Audio.Synthesi
protected override void AfterLoadInternal(Stack<ObjectModel> objectModels)
{
SynthesizedAudioObjectModel audio = objectModels.Pop() as SynthesizedAudioObjectModel;
for (int i = 1; i < audio.Tracks.Count; i++)
for (int i = 0; i < audio.Tracks.Count; i++)
{
SynthesizedAudioTrack track = audio.Tracks[i];
string text = string.Empty;
@ -108,7 +108,7 @@ namespace UniversalEditor.Plugins.Vocaloid.DataFormats.Multimedia.Audio.Synthesi
note.Phoneme = phonemeInfos[1];
note.Length = length;
note.Frequency = 128 - noteNumber;
track.Commands.Add(note);
note.Position = thisNotePosition;
if (grp.Items.IndexOf(prop) < grp.Items.Count - 1)
{
int nextNotePosition = int.Parse(grp.Items[grp.Items.IndexOf(prop) + 1].Name);
@ -120,6 +120,7 @@ namespace UniversalEditor.Plugins.Vocaloid.DataFormats.Multimedia.Audio.Synthesi
track.Commands.Add(rest);
}
}
track.Commands.Add(note);
break;
}
case "Singer":

View File

@ -37,6 +37,8 @@
<Compile Include="DataFormats\Multimedia\Audio\Voicebank\Vocaloid\VocaloidVoicebankDataFormat.cs" />
<Compile Include="DataFormats\Multimedia\Audio\VoicebankIndex\Vocaloid\DDIDataFormat.cs" />
<Compile Include="DataFormats\Multimedia\Audio\VoicebankIndex\Vocaloid\DDIParameter.cs" />
<Compile Include="DataFormats\Multimedia\Audio\Synthesized\Vocaloid\VPR\VPRSequenceJSONDataFormat.cs" />
<Compile Include="DataFormats\Multimedia\Audio\Synthesized\Vocaloid\VPR\VPRProjectZIPDataFormat.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="DataFormats\" />
@ -47,6 +49,7 @@
<Folder Include="DataFormats\Multimedia\Audio\Voicebank\" />
<Folder Include="DataFormats\Multimedia\Audio\Voicebank\Vocaloid\" />
<Folder Include="DataFormats\Multimedia\Audio\VoicebankIndex\" />
<Folder Include="DataFormats\Multimedia\Audio\Synthesized\Vocaloid\VPR\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Core\UniversalEditor.Core.csproj">
@ -61,6 +64,10 @@
<Project>{BE4D0BA3-0888-42A5-9C09-FC308A4509D2}</Project>
<Name>UniversalEditor.Plugins.Multimedia</Name>
</ProjectReference>
<ProjectReference Include="..\UniversalEditor.Plugins.FileSystem\UniversalEditor.Plugins.FileSystem.csproj">
<Project>{76FD1306-9CA4-428F-993B-B7E4EEEACBF3}</Project>
<Name>UniversalEditor.Plugins.FileSystem</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>