From aa4ffe769ad34fa0d2048752daef2d11794bda8f Mon Sep 17 00:00:00 2001 From: kbinani Date: Thu, 30 Jul 2009 15:02:59 +0000 Subject: [PATCH] git-svn-id: http://svn.sourceforge.jp/svnroot/lipsync@11 b1f601f4-4f45-0410-8980-aecacb008692 --- trunk/Boare.Lib.AppUtil/CursorUtil.cs | 210 +++++ trunk/Boare.Lib.AppUtil/DockPanelContainer.cs | 9 + trunk/Boare.Lib.AppUtil/MessageBodyEntry.cs | 31 + trunk/Boare.Lib.Media/MidiOutDevice.cs | 84 ++ trunk/Boare.Lib.Media/RawAvi2Writer.cs | 36 +- trunk/Boare.Lib.Vsq/AttackConfig.cs | 73 ++ trunk/Boare.Lib.Vsq/Boare.Lib.Vsq.csproj | 8 +- trunk/Boare.Lib.Vsq/ExpressionConfigSys.cs | 113 +++ trunk/Boare.Lib.Vsq/PortUtil.cs | 14 + trunk/Boare.Lib.Vsq/SMF/MidiFile.cs | 132 +-- trunk/Boare.Lib.Vsq/SingerConfig.cs | 180 ++-- trunk/Boare.Lib.Vsq/SingerConfigSys.cs | 142 ++++ trunk/Boare.Lib.Vsq/TextMemoryStream.cs | 155 ++-- trunk/Boare.Lib.Vsq/TransCodeUtil.cs | 32 + trunk/Boare.Lib.Vsq/UstEnvelope.cs | 78 ++ trunk/Boare.Lib.Vsq/UstPortamento.cs | 151 ++++ trunk/Boare.Lib.Vsq/UstVibrato.cs | 89 ++ trunk/Boare.Lib.Vsq/VibratoConfig.cs | 132 +++ trunk/Boare.Lib.Vsq/VibratoType.cs | 6 +- trunk/Boare.Lib.Vsq/VocaloSysUtil.cs | 791 ++++++++++++++++++ trunk/Boare.Lib.Vsq/VsqBPList.cs | 90 +- trunk/Boare.Lib.Vsq/VsqBPPair.cs | 15 + trunk/Boare.Lib.Vsq/VsqEventList.cs | 27 +- trunk/Boare.Lib.Vsq/VsqFile.cs | 323 +++---- trunk/Boare.Lib.Vsq/VsqMetaText/Handle.cs | 4 + trunk/Boare.Lib.Vsq/VsqMetaText/ID.cs | 26 +- .../Boare.Lib.Vsq/VsqMetaText/VsqMetaText.cs | 8 +- trunk/Boare.Lib.Vsq/VsqNrpn.cs | 50 +- trunk/Boare.Lib.Vsq/VsqTrack.cs | 43 +- trunk/Boare.Lib.Vsq/VsqVoiceLanguage.cs | 34 + 30 files changed, 2599 insertions(+), 487 deletions(-) create mode 100644 trunk/Boare.Lib.AppUtil/CursorUtil.cs create mode 100644 trunk/Boare.Lib.AppUtil/DockPanelContainer.cs create mode 100644 trunk/Boare.Lib.AppUtil/MessageBodyEntry.cs create mode 100644 trunk/Boare.Lib.Media/MidiOutDevice.cs create mode 100644 trunk/Boare.Lib.Vsq/AttackConfig.cs create mode 100644 trunk/Boare.Lib.Vsq/ExpressionConfigSys.cs create mode 100644 trunk/Boare.Lib.Vsq/SingerConfigSys.cs create mode 100644 trunk/Boare.Lib.Vsq/TransCodeUtil.cs create mode 100644 trunk/Boare.Lib.Vsq/UstEnvelope.cs create mode 100644 trunk/Boare.Lib.Vsq/UstPortamento.cs create mode 100644 trunk/Boare.Lib.Vsq/UstVibrato.cs create mode 100644 trunk/Boare.Lib.Vsq/VibratoConfig.cs create mode 100644 trunk/Boare.Lib.Vsq/VocaloSysUtil.cs create mode 100644 trunk/Boare.Lib.Vsq/VsqBPPair.cs create mode 100644 trunk/Boare.Lib.Vsq/VsqVoiceLanguage.cs diff --git a/trunk/Boare.Lib.AppUtil/CursorUtil.cs b/trunk/Boare.Lib.AppUtil/CursorUtil.cs new file mode 100644 index 0000000..9dfda41 --- /dev/null +++ b/trunk/Boare.Lib.AppUtil/CursorUtil.cs @@ -0,0 +1,210 @@ +#define RGB24 +using System; +using System.Runtime.InteropServices; +using System.Drawing; +using System.IO; +using System.Drawing.Imaging; + + +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.ComponentModel; +using System.Windows.Forms; +using System.IO; +using System.Runtime.InteropServices; +using System.Reflection; +using bocoree; + +namespace Boare.Lib.AppUtil { + + public static class CursorUtil { + public static void SaveAsIcon( Bitmap item, Stream stream, Color transp ) { + SaveCor( item, new Point( 0, 0 ), stream, 1, transp ); + } + + public static void SaveAsCursor( Bitmap item, Point hotspot, Stream stream, Color transp ) { + SaveCor( item, hotspot, stream, 2, transp ); + } + + private static void SaveCor( Bitmap item, Point hotspot, Stream stream, ushort type, Color transp ) { + IconFileHeader ifh = new IconFileHeader(); + ifh.icoReserved = 0x0; + ifh.icoResourceCount = 1; + ifh.icoResourceType = type; + ifh.Write( stream ); + IconInfoHeader iif = new IconInfoHeader(); + BITMAPINFOHEADER bih = new BITMAPINFOHEADER(); + iif.Width = (byte)item.Width; + iif.Height = (byte)item.Height; + iif.ColorCount = 0; + iif.Reserved1 = 0; + iif.Reserved2 = (ushort)hotspot.X; + iif.Reserved3 = (ushort)hotspot.Y; +#if RGB24 + int linesize = ((item.Width * 24 + 31) / 32) * 4; +#else + int linesize = ((item.Width * 32 + 31) / 32) * 4; +#endif + int linesize_mask = ((item.Width * 1 + 31) / 32) * 4; + int size = linesize * item.Height + linesize_mask * item.Height + 40; +#if DEBUG + Console.WriteLine( "linesize=" + linesize ); +#endif + iif.icoDIBSize = (uint)size; + iif.icoDIBOffset = 0x16; + iif.Write( stream ); + bih.biSize = 40; + bih.biWidth = item.Width; +#if RGB24 + bih.biHeight = item.Height * 2; +#else + bih.biHeight = item.Height * 2; +#endif + bih.biPlanes = 1; +#if RGB24 + bih.biBitCount = 24; +#else + bih.biBitCount = 32; +#endif + bih.biCompression = 0; + bih.biSizeImage = (uint)(linesize * item.Height); + bih.biXPelsPerMeter = 0;// (int)(item.HorizontalResolution / 2.54e-2); + bih.biYPelsPerMeter = 0;// (int)(item.VerticalResolution / 2.54e-2); + bih.biClrUsed = 0; + bih.biClrImportant = 0; + bih.Write( stream ); + for ( int y = item.Height - 1; y >= 0; y-- ) { + int count = 0; + for ( int x = 0; x < item.Width; x++ ) { + Color c = item.GetPixel( x, y ); + stream.WriteByte( (byte)c.B ); + stream.WriteByte( (byte)c.G ); + stream.WriteByte( (byte)c.R ); +#if DEBUG + if ( c.R != transp.R || c.G != transp.G || c.B != transp.B ) { + Console.WriteLine( "color=" + c ); + } +#endif +#if RGB24 + count += 3; +#else + stream.WriteByte( (byte)c.A ); + count += 4; +#endif + } + for ( int i = count; i < linesize; i++ ) { + stream.WriteByte( 0x0 ); + } + } + + for ( int y = item.Height - 1; y >= 0; y-- ) { + int count = 0; + byte v = 0x0; + int tcount = 0; + for ( int x = 0; x < item.Width; x++ ) { + Color c = item.GetPixel( x, y ); + byte tr = 0x0; + if ( c.R == transp.R && c.G == transp.G && c.B == transp.B ){ + tr = 0x1; + } + v = (byte)((byte)(v << 1) | (byte)(tr & 0x1)); + tcount++; + if ( tcount == 8 ) { + stream.WriteByte( v ); + count++; + tcount = 0; + v = 0x0; + } + } + if ( 0 < tcount ) { + v = (byte)(v << (9 - tcount)); + stream.WriteByte( v ); + count++; + } + for ( int i = count; i < linesize_mask; i++ ) { + stream.WriteByte( 0x0 ); + } + } + } + } + + [StructLayout( LayoutKind.Sequential, Pack = 1 )] + public struct IconFileHeader { + public ushort icoReserved; + public ushort icoResourceType; + public ushort icoResourceCount; + + public void Write( Stream stream ) { + byte[] buf; + buf = BitConverter.GetBytes( icoReserved ); + stream.Write( buf, 0, 2 ); + buf = BitConverter.GetBytes( icoResourceType ); + stream.Write( buf, 0, 2 ); + buf = BitConverter.GetBytes( icoResourceCount ); + stream.Write( buf, 0, 2 ); + } + + public static IconFileHeader Read( Stream fs ) { + IconFileHeader ifh = new IconFileHeader(); + byte[] buf = new byte[2]; + fs.Read( buf, 0, 2 ); + ifh.icoReserved = BitConverter.ToUInt16( buf, 0 ); + fs.Read( buf, 0, 2 ); + ifh.icoResourceType = BitConverter.ToUInt16( buf, 0 ); + fs.Read( buf, 0, 2 ); + ifh.icoResourceCount = BitConverter.ToUInt16( buf, 0 ); + return ifh; + } + } + + [StructLayout( LayoutKind.Sequential, Pack = 1 )] + public struct IconInfoHeader { + public byte Width; + public byte Height; + public byte ColorCount; + public byte Reserved1; + public ushort Reserved2; + public ushort Reserved3; + public uint icoDIBSize; + public uint icoDIBOffset; + + public override string ToString() { + return "{Width=" + Width + ", Height=" + Height + ", ColorCount=" + ColorCount + ", Reserved1=" + Reserved1 + ", Reserved2=" + Reserved2 + ", Reserved3=" + Reserved3 + ", icoDIBSize=" + icoDIBSize + ", icoDIBOffset=" + icoDIBOffset + "}"; + } + + public void Write( Stream stream ) { + byte[] buf; + stream.WriteByte( Width ); + stream.WriteByte( Height ); + stream.WriteByte( ColorCount ); + stream.WriteByte( Reserved1 ); + buf = BitConverter.GetBytes( Reserved2 ); + stream.Write( buf, 0, 2 ); + buf = BitConverter.GetBytes( Reserved3 ); + stream.Write( buf, 0, 2 ); + buf = BitConverter.GetBytes( icoDIBSize ); + stream.Write( buf, 0, 4 ); + buf = BitConverter.GetBytes( icoDIBOffset ); + stream.Write( buf, 0, 4 ); + } + + public static IconInfoHeader Read( Stream stream ) { + IconInfoHeader iih = new IconInfoHeader(); + iih.Width = (byte)stream.ReadByte(); + iih.Height = (byte)stream.ReadByte(); + iih.ColorCount = (byte)stream.ReadByte(); + iih.Reserved1 = (byte)stream.ReadByte(); + byte[] buf = new byte[4]; + stream.Read( buf, 0, 4 ); + iih.Reserved2 = BitConverter.ToUInt16( buf, 0 ); + iih.Reserved3 = BitConverter.ToUInt16( buf, 2 ); + stream.Read( buf, 0, 4 ); + iih.icoDIBSize = BitConverter.ToUInt32( buf, 0 ); + stream.Read( buf, 0, 4 ); + iih.icoDIBOffset = BitConverter.ToUInt32( buf, 0 ); + return iih; + } + } + +} diff --git a/trunk/Boare.Lib.AppUtil/DockPanelContainer.cs b/trunk/Boare.Lib.AppUtil/DockPanelContainer.cs new file mode 100644 index 0000000..c8784b2 --- /dev/null +++ b/trunk/Boare.Lib.AppUtil/DockPanelContainer.cs @@ -0,0 +1,9 @@ +using System; +using System.Windows.Forms; + +namespace Boare.Lib.AppUtil { + + public class DockPanelContainer : Panel { + } + +} diff --git a/trunk/Boare.Lib.AppUtil/MessageBodyEntry.cs b/trunk/Boare.Lib.AppUtil/MessageBodyEntry.cs new file mode 100644 index 0000000..21367cd --- /dev/null +++ b/trunk/Boare.Lib.AppUtil/MessageBodyEntry.cs @@ -0,0 +1,31 @@ +/* + * MessageBody.cs + * Copyright (c) 2009 kbinani + * + * This file is part of Boare.Lib.AppUtil. + * + * Boare.Lib.AppUtil is free software; you can redistribute it and/or + * modify it under the terms of the BSD License. + * + * Boare.Lib.AppUtil 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. + */ +using System; +using System.Collections.Generic; + +namespace Boare.Lib.AppUtil { + + public class MessageBodyEntry { + public string Message; + public List Location = new List(); + + public MessageBodyEntry( string message, string[] location ) { + Message = message; + for ( int i = 0; i < location.Length; i++ ) { + Location.Add( location[i] ); + } + } + } + +} diff --git a/trunk/Boare.Lib.Media/MidiOutDevice.cs b/trunk/Boare.Lib.Media/MidiOutDevice.cs new file mode 100644 index 0000000..a57c84f --- /dev/null +++ b/trunk/Boare.Lib.Media/MidiOutDevice.cs @@ -0,0 +1,84 @@ +/* + * MidiOutDevice.cs + * Copyright (c) 2009 kbinani + * + * This file is part of Boare.Lib.Media. + * + * Boare.Lib.Media is free software; you can redistribute it and/or + * modify it under the terms of the BSD License. + * + * Boare.Lib.Media 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. + */ +using System; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +using bocoree; + +namespace Boare.Lib.Media { + + public unsafe class MidiOutDevice { + private IntPtr m_handle; + private uint m_device_id; + + public MidiOutDevice( uint device_id ) { + m_device_id = device_id; + windows.midiOutOpen( ref m_handle, m_device_id, null, 0, windows.CALLBACK_NULL ); + } + + public void Close() { + if ( !m_handle.Equals( IntPtr.Zero ) ) { + windows.midiOutClose( m_handle ); + } + } + + public void ProgramChange( byte channel, byte program ) { + SendShort( new byte[] { (byte)(0xc0 | (channel & 0x0f)) , program, 0x0 } ); + } + + public void Play( byte channel, byte note, byte velocity ) { + SendShort( new byte[] { (byte)(0x90 | (channel & 0x0f)), note, velocity } ); + } + + public void SendData( byte[] data ) { + if ( 0 < data.Length && data.Length <= 4 ) { + SendShort( data ); + } else { + SendLong( data ); + } + } + + private void SendShort( byte[] data ) { + uint message = 0; + for ( int i = 0; i < data.Length; i++ ) { + message |= ((uint)data[i]) << (i * 8); + } + windows.midiOutShortMsg( m_handle, message ); + } + + private void SendLong( byte[] data ) { + MIDIHDR hdr = new MIDIHDR(); + GCHandle dataHandle = GCHandle.Alloc( data, GCHandleType.Pinned ); + uint size = (uint)sizeof( MIDIHDR ); + try { + hdr.lpData = (byte*)dataHandle.AddrOfPinnedObject().ToPointer(); + hdr.dwBufferLength = (uint)data.Length; + hdr.dwFlags = 0; + windows.midiOutPrepareHeader( m_handle, ref hdr, size ); + while ( (hdr.dwFlags & windows.WHDR_PREPARED) != windows.WHDR_PREPARED ) { + Application.DoEvents(); + } + windows.midiOutLongMsg( m_handle, ref hdr, size ); + while ( (hdr.dwFlags & windows.WHDR_DONE) != windows.WHDR_DONE ) { + Application.DoEvents(); + } + windows.midiOutUnprepareHeader( m_handle, ref hdr, size ); + } finally { + dataHandle.Free(); + } + } + } + +} diff --git a/trunk/Boare.Lib.Media/RawAvi2Writer.cs b/trunk/Boare.Lib.Media/RawAvi2Writer.cs index 9ea4f0b..35498ee 100644 --- a/trunk/Boare.Lib.Media/RawAvi2Writer.cs +++ b/trunk/Boare.Lib.Media/RawAvi2Writer.cs @@ -165,7 +165,7 @@ namespace Boare.Lib.Media { } } - public class RawAvi2Writer { + public class RawAvi2Writer : IAviWriter { public MainAVIHeader m_main_header; public AVIStreamHeader m_stream_header; //long currentIndex; @@ -187,6 +187,26 @@ namespace Boare.Lib.Media { int m_junk_length; uint m_scale; uint m_rate; + private int m_width; + private int m_height; + + public Size Size { + get { + return new Size( m_width, m_height ); + } + } + + public uint Scale { + get { + return m_scale; + } + } + + public uint Rate { + get { + return m_rate; + } + } internal float frameRate { get { @@ -200,7 +220,10 @@ namespace Boare.Lib.Media { /// /// 書き込み対象のファイル /// AVIファイルのフレームレート - public void Open( string file, uint scale, uint rate ) { + // string file, uint scale, uint rate, int width, int height, IntPtr hwnd + public bool Open( string file, uint scale, uint rate, int width, int height, IntPtr hwnd ) { + m_width = width; + m_height = height; this.m_stream = new BinaryWriter( new FileStream( file, FileMode.Create, FileAccess.Write ) ); float fps = (float)rate / (float)scale; this.m_main_header.dwMicroSecPerFrame = (uint)(1.0e6 / fps);// ! 1秒は10^6μ秒 @@ -226,6 +249,7 @@ namespace Boare.Lib.Media { m_std_index = new AVISTDINDEX( 0L ); m_super_index = new AVISUPERINDEX( 0 ); m_riff_position = 0x4; + return true; } @@ -361,6 +385,10 @@ namespace Boare.Lib.Media { public void AddFrame( Bitmap bmp ) { int i, width, height, lineSize; + if ( bmp.Width != m_width || bmp.Height != m_height ) { + throw new Exception( "bitmap size mismatch" ); + } + // BitmapDataからビットマップデータと、BITMPAINFOHEADERを取り出す BitmapData bmpDat = bmp.LockBits( new Rectangle( 0, 0, (int)bmp.Width, (int)bmp.Height ), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb ); @@ -370,8 +398,8 @@ namespace Boare.Lib.Media { if ( m_is_first ) {//then m_is_first = false; - this.m_main_header.dwWidth = (uint)bmpDat.Width;// bmp%infoHeader%Width - this.m_main_header.dwHeight = (uint)bmpDat.Height;// bmp%infoHeader%Height + this.m_main_header.dwWidth = (uint)m_width; + this.m_main_header.dwHeight = (uint)m_height; this.m_main_header.dwMaxBytesPerSec = (uint)(bmpDat.Stride * bmpDat.Height * this.frameRate);// bmp%infoHeader%SizeImage * avi%frameRate this.m_main_header.dwStreams = 1; this.m_main_header.dwSuggestedBufferSize = (uint)(bmpDat.Stride * bmpDat.Height);// bmp.infoHeader%SizeImage diff --git a/trunk/Boare.Lib.Vsq/AttackConfig.cs b/trunk/Boare.Lib.Vsq/AttackConfig.cs new file mode 100644 index 0000000..9b07c62 --- /dev/null +++ b/trunk/Boare.Lib.Vsq/AttackConfig.cs @@ -0,0 +1,73 @@ +/* + * AttackConfig.cs + * Copyright (c) 2009 kbinani + * + * This file is part of Boare.Lib.Vsq. + * + * Boare.Lib.Vsq is free software; you can redistribute it and/or + * modify it under the terms of the BSD License. + * + * Boare.Lib.Vsq 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. + */ +using System; +using System.IO; + +namespace Boare.Lib.Vsq { + + public class AttackConfig { + public int number; + public String file; + public String author; + public String vendor; + public NoteHeadHandle contents; + + public AttackConfig() { + contents = new NoteHeadHandle(); + } + + public void parseAic( String aic_file ) { + using ( StreamReader sr = new StreamReader( aic_file ) ) { + String line; + String current_entry = ""; + String articulation = ""; + while ( (line = sr.ReadLine()) != null ) { + if ( line.StartsWith( "[" ) ) { + current_entry = line; + continue; + } else if ( line == "" || line.StartsWith( ";" ) ) { + continue; + } + + String[] spl = line.Split( new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries ); + if ( spl.Length < 2 ) { + continue; + } + spl[0] = spl[0].Trim(); + spl[1] = spl[1].Trim(); + if ( current_entry == "[Common]" ) { + if ( spl[0] == "Articulation" ) { + articulation = spl[1]; + } + } else if ( current_entry == "[Parameter]" ) { + if ( spl[0] == "Length" ) { + try { + this.contents.Length = int.Parse( spl[1] ); + } catch { } + } else if ( spl[0] == "Duration" ) { + try { + this.contents.Duration = int.Parse( spl[1] ); + } catch { } + } else if ( spl[0] == "Depth" ) { + try { + this.contents.Depth = int.Parse( spl[1] ); + } catch { } + } + } + } + } + } + } + +} diff --git a/trunk/Boare.Lib.Vsq/Boare.Lib.Vsq.csproj b/trunk/Boare.Lib.Vsq/Boare.Lib.Vsq.csproj index af7814a..28ee08f 100644 --- a/trunk/Boare.Lib.Vsq/Boare.Lib.Vsq.csproj +++ b/trunk/Boare.Lib.Vsq/Boare.Lib.Vsq.csproj @@ -2,7 +2,7 @@ Debug AnyCPU - 9.0.30729 + 9.0.21022 2.0 {673347F3-6FC2-4F82-9273-BF158E0F8CB1} Library @@ -59,6 +59,7 @@ + @@ -66,6 +67,7 @@ + @@ -74,9 +76,11 @@ + + - + diff --git a/trunk/Boare.Lib.Vsq/ExpressionConfigSys.cs b/trunk/Boare.Lib.Vsq/ExpressionConfigSys.cs new file mode 100644 index 0000000..1b42411 --- /dev/null +++ b/trunk/Boare.Lib.Vsq/ExpressionConfigSys.cs @@ -0,0 +1,113 @@ +/* + * ExpressionConfigSys.cs + * Copyright (c) 2009 kbinani + * + * This file is part of Boare.Lib.Vsq. + * + * Boare.Lib.Vsq is free software; you can redistribute it and/or + * modify it under the terms of the BSD License. + * + * Boare.Lib.Vsq 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. + */ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Boare.Lib.Vsq { + + public class ExpressionConfigSys { + private const int MAX_VIBRATO = 0x400; + private List m_vibrato_configs; + private List m_attack_configs; + + public ExpressionConfigSys( String path_expdb ) { + m_vibrato_configs = new List(); + m_attack_configs = new List(); + String expression = Path.Combine( path_expdb, "expression.map" ); + if ( !File.Exists( expression ) ) { + return; + } + + using ( FileStream fs = new FileStream( expression, FileMode.Open, FileAccess.Read ) ) { + byte[] dat = new byte[8]; + fs.Seek( 0x20, SeekOrigin.Begin ); + for ( int i = 0; i < MAX_VIBRATO; i++ ) { + fs.Read( dat, 0, 8 ); + ulong value = VocaloSysUtil.makelong_le( dat ); + + if ( value <= 0 ) { + continue; + } + + String ved = Path.Combine( path_expdb, "vexp" + value + ".ved" ); + if ( !File.Exists( ved ) ) { + continue; + } + String vexp_dir = Path.Combine( path_expdb, "vexp" + value ); + if ( !Directory.Exists( vexp_dir ) ) { + continue; + } + + string NL = (char)0x0D + "" + (char)0x0A; + using ( FileStream fs_ved = new FileStream( ved, FileMode.Open, FileAccess.Read ) ){ + byte[] byte_ved = new byte[fs_ved.Length]; + fs_ved.Read( byte_ved, 0, byte_ved.Length ); + TransCodeUtil.decodeBytes( ref byte_ved ); + String str = new String( Encoding.ASCII.GetChars( byte_ved ) ); + String[] spl = str.Split( new String[]{ NL }, StringSplitOptions.RemoveEmptyEntries ); + String current_entry = ""; + for ( int j = 0; j < spl.Length; j++ ) { + if ( spl[j].StartsWith( "[" ) ) { + current_entry = spl[j]; + continue; + } else if ( spl[j] == "" ) { + continue; + } + if ( current_entry.Equals( "[VIBRATO]" ) ) { + String[] spl2 = spl[j].Split( ',' ); + if ( spl2.Length < 6 ) { + continue; + } + // ex: 1,1,"normal","normal2_type1.aic","[Normal]:Type:1","Standard","YAMAHA",0 + VibratoConfig item = new VibratoConfig(); + item.number = int.Parse( spl2[0] ); + item.contents.IDS = spl2[2].Replace( "\"", "" ); + item.file = spl2[3].Replace( "\"", "" ); + item.contents.Caption = spl2[4].Replace( ":", " " ).Replace( "\"", "" ); + item.author = spl2[5].Replace( "\"", "" ); + item.vendor = spl2[6].Replace( "\"", "" ); + String aic_file = Path.Combine( vexp_dir, item.file ); + if ( !File.Exists( aic_file ) ) { + continue; + } + item.parseAic( aic_file ); + } if ( current_entry == "[NOTEATTACK]" ) { + String[] spl2 = spl[j].Split( ',' ); + if ( spl2.Length < 6 ) { + continue; + } + // ex: 1,1,"normal","normal2_type1.aic","[Normal]:Type:1","Standard","YAMAHA",0 + AttackConfig item = new AttackConfig(); + item.number = int.Parse( spl2[0] ); + item.contents.IDS = spl2[2].Replace( "\"", "" ); + item.file = spl2[3].Replace( "\"", "" ); + item.contents.Caption = spl2[4].Replace( ":", " " ).Replace( "\"", "" ); + item.author = spl2[5].Replace( "\"", "" ); + item.vendor = spl2[6].Replace( "\"", "" ); + String aic_file = Path.Combine( vexp_dir, item.file ); + if ( !File.Exists( aic_file ) ) { + continue; + } + item.parseAic( aic_file ); + } + } + } + } + } + } + } + +} diff --git a/trunk/Boare.Lib.Vsq/PortUtil.cs b/trunk/Boare.Lib.Vsq/PortUtil.cs index 9ddfc8c..cbb9e48 100644 --- a/trunk/Boare.Lib.Vsq/PortUtil.cs +++ b/trunk/Boare.Lib.Vsq/PortUtil.cs @@ -16,6 +16,20 @@ using System.Collections.Generic; namespace Boare.Lib.Vsq { + public class Vector : List { + public int size() { + return base.Count; + } + + public T get( int index ) { + return base[index]; + } + + public void set( int index, T value ) { + base[index] = value; + } + } + public interface Iterator { bool hasNext(); object next(); diff --git a/trunk/Boare.Lib.Vsq/SMF/MidiFile.cs b/trunk/Boare.Lib.Vsq/SMF/MidiFile.cs index aa7e39a..5a4b9cb 100644 --- a/trunk/Boare.Lib.Vsq/SMF/MidiFile.cs +++ b/trunk/Boare.Lib.Vsq/SMF/MidiFile.cs @@ -21,9 +21,36 @@ namespace Boare.Lib.Vsq { /// midiイベント。メタイベントは、メタイベントのデータ長をData[1]に格納せず、生のデータをDataに格納するので、注意が必要 /// public struct MidiEvent : IComparable { - public long Clock; - public byte FirstByte; - public byte[] Data; + public long clock; + public byte firstByte; + public byte[] data; + + public long Clock { + get { + return clock; + } + set { + clock = value; + } + } + + public byte FirstByte { + get { + return firstByte; + } + set { + firstByte = value; + } + } + + public byte[] Data { + get { + return data; + } + set { + data = value; + } + } private static void writeDeltaClock( Stream stream, long number ) { bool[] bits = new bool[64]; @@ -96,10 +123,10 @@ namespace Boare.Lib.Vsq { // 3byte使用するシステムメッセージ // 0xF2: ソングポジション・ポインタ MidiEvent me = new MidiEvent(); - me.Clock = last_clock; - me.FirstByte = first_byte; - me.Data = new byte[2]; - stream.Read( me.Data, 0, 2 ); + me.clock = last_clock; + me.firstByte = first_byte; + me.data = new byte[2]; + stream.Read( me.data, 0, 2 ); return me; } else if ( ctrl == 0xC0 || ctrl == 0xD0 || first_byte == 0xF1 || first_byte == 0xF2 ) { // 2byte使用するチャンネルメッセージ @@ -109,10 +136,10 @@ namespace Boare.Lib.Vsq { // 0xF1: クォータフレーム // 0xF3: ソングセレクト MidiEvent me = new MidiEvent(); - me.Clock = last_clock; - me.FirstByte = first_byte; - me.Data = new byte[1]; - stream.Read( me.Data, 0, 1 ); + me.clock = last_clock; + me.firstByte = first_byte; + me.data = new byte[1]; + stream.Read( me.data, 0, 1 ); return me; } else if ( first_byte == 0xF6 ) { // 1byte使用するシステムメッセージ @@ -125,38 +152,38 @@ namespace Boare.Lib.Vsq { // 0xFE: アクティブセンシング // 0xFF: システムリセット MidiEvent me = new MidiEvent(); - me.Clock = last_clock; - me.FirstByte = first_byte; - me.Data = new byte[0]; + me.clock = last_clock; + me.firstByte = first_byte; + me.data = new byte[0]; return me; } else if ( first_byte == 0xff ) { // メタイベント byte meta_event_type = (byte)stream.ReadByte(); long meta_event_length = readDeltaClock( stream ); MidiEvent me = new MidiEvent(); - me.Clock = last_clock; - me.FirstByte = first_byte; - me.Data = new byte[meta_event_length + 1]; - me.Data[0] = meta_event_type; - stream.Read( me.Data, 1, (int)meta_event_length ); + me.clock = last_clock; + me.firstByte = first_byte; + me.data = new byte[meta_event_length + 1]; + me.data[0] = meta_event_type; + stream.Read( me.data, 1, (int)meta_event_length ); return me; } else if ( first_byte == 0xf0 ) { // f0ステータスのSysEx MidiEvent me = new MidiEvent(); - me.Clock = last_clock; - me.FirstByte = first_byte; + me.clock = last_clock; + me.firstByte = first_byte; long sysex_length = readDeltaClock( stream ); - me.Data = new byte[sysex_length + 1]; - stream.Read( me.Data, 0, (int)(sysex_length + 1) ); + me.data = new byte[sysex_length + 1]; + stream.Read( me.data, 0, (int)(sysex_length + 1) ); return me; } else if ( first_byte == 0xf7 ) { // f7ステータスのSysEx MidiEvent me = new MidiEvent(); - me.Clock = last_clock; - me.FirstByte = first_byte; + me.clock = last_clock; + me.firstByte = first_byte; long sysex_length = readDeltaClock( stream ); - me.Data = new byte[sysex_length]; - stream.Read( me.Data, 0, (int)sysex_length ); + me.data = new byte[sysex_length]; + stream.Read( me.data, 0, (int)sysex_length ); return me; } else { throw new ApplicationException( "don't know how to process first_byte: 0x" + Convert.ToString( first_byte, 16 ) ); @@ -164,40 +191,43 @@ namespace Boare.Lib.Vsq { } public void writeData( Stream stream ) { - stream.WriteByte( FirstByte ); - if ( FirstByte == 0xff ) { - stream.WriteByte( Data[0] ); - writeDeltaClock( stream, Data.Length - 1 ); + stream.WriteByte( firstByte ); + if ( firstByte == 0xff ) { + stream.WriteByte( data[0] ); + writeDeltaClock( stream, data.Length - 1 ); //stream.WriteByte( (byte)(Data.Length - 1) ); - stream.Write( Data, 1, Data.Length - 1 ); + stream.Write( data, 1, data.Length - 1 ); } else { - stream.Write( Data, 0, Data.Length ); + stream.Write( data, 0, data.Length ); } } public int CompareTo( MidiEvent item ) { - return (int)(Clock - item.Clock); + return (int)(clock - item.clock); } public static MidiEvent generateTimeSigEvent( int clock, int numerator, int denominator ) { MidiEvent ret = new MidiEvent(); - ret.Clock = clock; - ret.FirstByte = 0xff; - byte b_numer = (byte)(Math.Log( numerator, 2 ) + 0.1); - ret.Data = new byte[5] { 0x58, (byte)denominator, b_numer, 0x18, 0x08 }; + ret.clock = clock; + ret.firstByte = 0xff; + byte b_numer = (byte)(Math.Log( denominator, 2 ) + 0.1); +#if DEBUG + Console.WriteLine( "VsqEvent.generateTimeSigEvent; b_number=" + b_numer + "; denominator=" + denominator ); +#endif + ret.data = new byte[5] { 0x58, (byte)numerator, b_numer, 0x18, 0x08 }; return ret; } public static MidiEvent generateTempoChangeEvent( int clock, int tempo ) { MidiEvent ret = new MidiEvent(); - ret.Clock = clock; - ret.FirstByte = 0xff; + ret.clock = clock; + ret.firstByte = 0xff; byte b1 = (byte)(tempo & 0xff); tempo = tempo >> 8; byte b2 = (byte)(tempo & 0xff); tempo = tempo >> 8; byte b3 = (byte)(tempo & 0xff); - ret.Data = new byte[4] { 0x51, b3, b2, b1 }; + ret.data = new byte[4] { 0x51, b3, b2, b1 }; return ret; } } @@ -259,7 +289,7 @@ namespace Boare.Lib.Vsq { int count = m_events[track].Count; for ( int i = 0; i < count; i++ ) { MidiEvent mi = m_events[track][i]; - mi.Clock = mi.Clock * 480 / m_time_format; + mi.clock = mi.clock * 480 / m_time_format; m_events[track][i] = mi; } } @@ -275,36 +305,36 @@ namespace Boare.Lib.Vsq { byte msb, lsb, data_msb, data_lsb; msb = lsb = data_msb = data_lsb = 0x0; for ( int i = 0; i < m_events[track].Count; i++ ) { - if ( m_events[track][i].FirstByte == 0xb0 ) { - switch ( m_events[track][i].Data[0] ) { + if ( m_events[track][i].firstByte == 0xb0 ) { + switch ( m_events[track][i].data[0] ) { case 0x63: - msb = m_events[track][i].Data[1]; + msb = m_events[track][i].data[1]; lsb = 0x0; break; case 0x62: - lsb = m_events[track][i].Data[1]; + lsb = m_events[track][i].data[1]; break; case 0x06: - data_msb = m_events[track][i].Data[1]; + data_msb = m_events[track][i].data[1]; ushort nrpn = (ushort)(msb << 8 | lsb); string name = NRPN.getName( nrpn ); if ( name == "" ) { name = "* * UNKNOWN * *"; - sw.WriteLine( string.Format( format0, m_events[track][i].Clock, nrpn, name, data_msb ) ); + sw.WriteLine( string.Format( format0, m_events[track][i].clock, nrpn, name, data_msb ) ); } else { //if ( !NRPN.is_require_data_lsb( nrpn ) ) { - sw.WriteLine( string.Format( format0, m_events[track][i].Clock, nrpn, name, data_msb ) ); + sw.WriteLine( string.Format( format0, m_events[track][i].clock, nrpn, name, data_msb ) ); //} } break; case 0x26: - data_lsb = m_events[track][i].Data[1]; + data_lsb = m_events[track][i].data[1]; ushort nrpn2 = (ushort)(msb << 8 | lsb); string name2 = NRPN.getName( nrpn2 ); if ( name2 == "" ) { name2 = "* * UNKNOWN * *"; } - sw.WriteLine( string.Format( format, m_events[track][i].Clock, nrpn2, name2, data_msb, data_lsb ) ); + sw.WriteLine( string.Format( format, m_events[track][i].clock, nrpn2, name2, data_msb, data_lsb ) ); break; } } diff --git a/trunk/Boare.Lib.Vsq/SingerConfig.cs b/trunk/Boare.Lib.Vsq/SingerConfig.cs index 4c5700b..561b0fc 100644 --- a/trunk/Boare.Lib.Vsq/SingerConfig.cs +++ b/trunk/Boare.Lib.Vsq/SingerConfig.cs @@ -29,6 +29,19 @@ namespace Boare.Lib.Vsq { public int GenderFactor; public int Original; public int Program; + public int Resonance1Amplitude; + public int Resonance1Frequency; + public int Resonance1BandWidth; + public int Resonance2Amplitude; + public int Resonance2Frequency; + public int Resonance2BandWidth; + public int Resonance3Amplitude; + public int Resonance3Frequency; + public int Resonance3BandWidth; + public int Resonance4Amplitude; + public int Resonance4Frequency; + public int Resonance4BandWidth; + public int Harmonics; public SingerConfig() { } @@ -46,96 +59,23 @@ namespace Boare.Lib.Vsq { ret.GenderFactor = GenderFactor; ret.Original = Original; ret.Program = Program; + ret.Resonance1Amplitude = Resonance1Amplitude; + ret.Resonance1Frequency = Resonance1Frequency; + ret.Resonance1BandWidth = Resonance1BandWidth; + ret.Resonance2Amplitude = Resonance2Amplitude; + ret.Resonance2Frequency = Resonance2Frequency; + ret.Resonance2BandWidth = Resonance2BandWidth; + ret.Resonance3Amplitude = Resonance3Amplitude; + ret.Resonance3Frequency = Resonance3Frequency; + ret.Resonance3BandWidth = Resonance3BandWidth; + ret.Resonance4Amplitude = Resonance4Amplitude; + ret.Resonance4Frequency = Resonance4Frequency; + ret.Resonance4BandWidth = Resonance4BandWidth; + ret.Harmonics = Harmonics; return ret; } - public static void decode_vvd_bytes( ref byte[] dat ) { - for ( int i = 0; i < dat.Length; i++ ) { - byte M = (byte)(dat[i] >> 4); - byte L = (byte)(dat[i] - (M << 4)); - byte newM = endecode_vvd_m( M ); - byte newL = endecode_vvd_l( L ); - dat[i] = (byte)((newM << 4) | newL); - } - } - - static byte endecode_vvd_l( byte value ) { - switch ( value ) { - case 0x0: - return 0xa; - case 0x1: - return 0xb; - case 0x2: - return 0x8; - case 0x3: - return 0x9; - case 0x4: - return 0xe; - case 0x5: - return 0xf; - case 0x6: - return 0xc; - case 0x7: - return 0xd; - case 0x8: - return 0x2; - case 0x9: - return 0x3; - case 0xa: - return 0x0; - case 0xb: - return 0x1; - case 0xc: - return 0x6; - case 0xd: - return 0x7; - case 0xe: - return 0x4; - case 0xf: - return 0x5; - } - return 0x0; - } - - static byte endecode_vvd_m( byte value ) { - switch ( value ) { - case 0x0: - return 0x1; - case 0x1: - return 0x0; - case 0x2: - return 0x3; - case 0x3: - return 0x2; - case 0x4: - return 0x5; - case 0x5: - return 0x4; - case 0x6: - return 0x7; - case 0x7: - return 0x6; - case 0x8: - return 0x9; - case 0x9: - return 0x8; - case 0xa: - return 0xb; - case 0xb: - return 0xa; - case 0xc: - return 0xd; - case 0xd: - return 0xc; - case 0xe: - return 0xf; - case 0xf: - return 0xe; - } - return 0x0; - } - - public static SingerConfig readSingerConfig( string file, int original ) { + public static SingerConfig fromVvd( string file, int original ) { SingerConfig sc = new SingerConfig(); //original = original; sc.ID = "VOCALOID:VIRTUAL:VOICE"; @@ -154,14 +94,11 @@ namespace Boare.Lib.Vsq { int length = (int)fs.Length; byte[] dat = new byte[length]; fs.Read( dat, 0, length ); - decode_vvd_bytes( ref dat ); - for ( int i = 0; i < dat.Length - 1; i++ ) { - if ( dat[i] == 0x17 && dat[i + 1] == 0x10 ) { - dat[i] = 0x0d; - dat[i + 1] = 0x0a; - } - } + TransCodeUtil.decodeBytes( ref dat ); string str = bocoree.cp932.convert( dat ); +#if DEBUG + Console.WriteLine( "SingerConfig.readSingerConfig; str=" + str ); +#endif string crlf = ((char)0x0d).ToString() + ((char)0x0a).ToString(); string[] spl = str.Split( new string[] { crlf }, StringSplitOptions.RemoveEmptyEntries ); @@ -176,6 +113,8 @@ namespace Boare.Lib.Vsq { id = id.Substring( 1, id.Length - 2 ); value = value.Substring( 1, value.Length - 2 ); value = value.Replace( "\\\"", "\"" ); + int parsed_int = 64; + int.TryParse( value, out parsed_int ); if ( id == "ID" ) { sc.ID = value; } else if ( id == "FORMAT" ) { @@ -184,31 +123,42 @@ namespace Boare.Lib.Vsq { sc.VOICEIDSTR = value; } else if ( id == "VOICENAME" ) { sc.VOICENAME = value; - } else if ( id == "Breathiness" ) { - try { - sc.Breathiness = int.Parse( value ); - } catch { - } + } else if ( id == "Breathiness" || id == "Noise" ) { + sc.Breathiness = parsed_int; } else if ( id == "Brightness" ) { - try { - sc.Brightness = int.Parse( value ); - } catch { - } + sc.Brightness = parsed_int; } else if ( id == "Clearness" ) { - try { - sc.Clearness = int.Parse( value ); - } catch { - } + sc.Clearness = parsed_int; } else if ( id == "Opening" ) { - try { - sc.Opening = int.Parse( value ); - } catch { - } + sc.Opening = parsed_int; } else if ( id == "Gender:Factor" ) { - try { - sc.GenderFactor = int.Parse( value ); - } catch { - } + sc.GenderFactor = parsed_int; + } else if ( id == "Resonance1:Frequency" ) { + sc.Resonance1Frequency = parsed_int; + } else if ( id == "Resonance1:Band:Width" ) { + sc.Resonance1BandWidth = parsed_int; + } else if ( id == "Resonance1:Amplitude" ) { + sc.Resonance1Amplitude = parsed_int; + } else if ( id == "Resonance2:Frequency" ) { + sc.Resonance2Frequency = parsed_int; + } else if ( id == "Resonance2:Band:Width" ) { + sc.Resonance2BandWidth = parsed_int; + } else if ( id == "Resonance2:Amplitude" ) { + sc.Resonance2Amplitude = parsed_int; + } else if ( id == "Resonance3:Frequency" ) { + sc.Resonance3Frequency = parsed_int; + } else if ( id == "Resonance3:Band:Width" ) { + sc.Resonance3BandWidth = parsed_int; + } else if ( id == "Resonance3:Amplitude" ) { + sc.Resonance3Amplitude = parsed_int; + } else if ( id == "Resonance4:Frequency" ) { + sc.Resonance4Frequency = parsed_int; + } else if ( id == "Resonance4:Band:Width" ) { + sc.Resonance4BandWidth = parsed_int; + } else if ( id == "Resonance4:Amplitude" ) { + sc.Resonance4Amplitude = parsed_int; + } else if ( id == "Harmonics" ) { + sc.Harmonics = parsed_int; } } } catch { diff --git a/trunk/Boare.Lib.Vsq/SingerConfigSys.cs b/trunk/Boare.Lib.Vsq/SingerConfigSys.cs new file mode 100644 index 0000000..4383dce --- /dev/null +++ b/trunk/Boare.Lib.Vsq/SingerConfigSys.cs @@ -0,0 +1,142 @@ +/* + * SingerConfigSys.cs + * Copyright (c) 2009 kbinani + * + * This file is part of Boare.Lib.Vsq. + * + * Boare.Lib.Vsq is free software; you can redistribute it and/or + * modify it under the terms of the BSD License. + * + * Boare.Lib.Vsq 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. + */ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Boare.Lib.Vsq { + + public class SingerConfigSys { + private const int MAX_SINGERS = 0x4000; + + private List m_installed_singers = new List(); + private List m_singer_configs = new List(); + + /// + /// + /// + /// 音源のデータディレクトリ(ex:"C:\Program Files\VOCALOID2\voicedbdir") + /// 音源のインストールディレクトリ(ex:new string[]{ "C:\Program Files\VOCALOID2\voicedbdir\BXXXXXXXXXXXXXXX", "D:\singers\BNXXXXXXXXXX" }) + public SingerConfigSys( string path_voicedb, string[] path_installed_singers ) { + m_installed_singers = new List(); + m_singer_configs = new List(); + String map = Path.Combine( path_voicedb, "voice.map" ); + if ( !File.Exists( map ) ) { + return; + } + using ( FileStream fs = new FileStream( map, FileMode.Open, FileAccess.Read ) ) { + byte[] dat = new byte[8]; + fs.Seek( 0x20, SeekOrigin.Begin ); + for ( int i = 0; i < MAX_SINGERS; i++ ) { + fs.Read( dat, 0, 8 ); + ulong value = VocaloSysUtil.makelong_le( dat ); + if ( value >= 1 ) { + String vvd = Path.Combine( path_voicedb, "vvoice" + value + ".vvd" ); + SingerConfig item = SingerConfig.fromVvd( vvd, 0 ); + item.Program = i; + + int original = -1; + foreach ( SingerConfig sc in m_installed_singers ) { + if ( sc.VOICEIDSTR == item.VOICEIDSTR ) { + original = sc.Program; + break; + } + } + if ( original < 0 ) { + foreach ( String ipath in path_installed_singers ) { + if ( ipath.EndsWith( item.VOICEIDSTR ) ) { + string[] vvds = Directory.GetFiles( ipath, "*.vvd" ); + if ( vvds.Length > 0 ) { + original = m_installed_singers.Count; + SingerConfig installed = SingerConfig.fromVvd( vvds[0], original ); + installed.Program = original; + m_installed_singers.Add( installed ); + break; + } + } + } + } + + item.Original = original; + m_singer_configs.Add( item ); + } + } + } + } + + public SingerConfig[] getInstalledSingers() { + return m_installed_singers.ToArray(); + } + + /// + /// Gets the VsqID of program change. + /// + /// + /// + public VsqID getSingerID( string singer ) { + VsqID ret = new VsqID( 0 ); + ret.type = VsqIDType.Singer; + SingerConfig sc = null; + for ( int i = 0; i < m_singer_configs.Count; i++ ) { + if ( m_singer_configs[i].VOICENAME == singer ) { + sc = m_singer_configs[i]; + break; + } + } + if ( sc == null ) { + sc = new SingerConfig(); + } + int lang = 0; + foreach ( SingerConfig sc2 in m_installed_singers ) { + if ( sc.VOICEIDSTR == sc2.VOICEIDSTR ) { + lang = (int)VocaloSysUtil.getLanguageFromName( sc.VOICENAME ); + break; + } + } + ret.IconHandle = new IconHandle(); + ret.IconHandle.IconID = "$0701" + sc.Program.ToString( "0000" ); + ret.IconHandle.IDS = sc.VOICENAME; + ret.IconHandle.Index = 0; + ret.IconHandle.Language = lang; + ret.IconHandle.Length = 1; + ret.IconHandle.Original = sc.Original; + ret.IconHandle.Program = sc.Program; + ret.IconHandle.Caption = ""; + return ret; + } + + /// + /// Gets the singer information of pecified program change. + /// + /// + /// + public SingerConfig getSingerInfo( string singer ) { + foreach ( SingerConfig item in m_singer_configs ) { + if ( item.VOICENAME == singer ) { + return item; + } + } + return null; + } + + /// + /// Gets the list of singer configs. + /// + /// + public SingerConfig[] getSingerConfigs() { + return m_singer_configs.ToArray(); + } + } + +} diff --git a/trunk/Boare.Lib.Vsq/TextMemoryStream.cs b/trunk/Boare.Lib.Vsq/TextMemoryStream.cs index cecb7c5..f656b63 100644 --- a/trunk/Boare.Lib.Vsq/TextMemoryStream.cs +++ b/trunk/Boare.Lib.Vsq/TextMemoryStream.cs @@ -18,109 +18,86 @@ using System.Collections.Generic; namespace Boare.Lib.Vsq { - /// - /// メモリー上でテキストファイルを扱うためのクラス. - /// public class TextMemoryStream : IDisposable { - FileAccess m_access; - MemoryStream m_ms = null; - Encoding m_enc; - byte[] NEW_LINE; + private static readonly string NL = (char)0x0d + "" + (char)0x0a; + + private List m_lines; + private int m_index; + + public TextMemoryStream() { + m_lines = new List(); + m_lines.Add( "" ); + m_index = 0; + } + + public TextMemoryStream( string path, Encoding encoding ) { + m_lines = new List(); + m_index = 0; + if ( File.Exists( path ) ) { + using ( StreamReader sr = new StreamReader( path, encoding ) ) { + while ( sr.Peek() >= 0 ) { + string line = sr.ReadLine(); + m_lines.Add( line ); + m_index++; + } + } + } + } - /// - /// - /// - /// public void write( string value ) { - byte[] buff = m_enc.GetBytes( value ); - m_ms.Write( buff, 0, buff.Length ); + appendString( value ); + } + + public void writeLine( string value ) { + appendString( value + NL ); + } + + private void appendString( string value ) { + string[] lines = value.Split( new string[] { NL }, StringSplitOptions.None ); + List lines2 = new List(); + for ( int i = 0; i < lines.Length; i++ ) { + string[] spl = lines[i].Split( (char)0x0d, (char)0x0a ); + for ( int j = 0; j < spl.Length; j++ ) { + lines2.Add( spl[j] ); + } + } + int count = lines2.Count; + if ( count > 0 ) { + m_lines[m_index] += lines2[0]; + for ( int i = 1; i < count; i++ ) { + m_lines.Add( lines2[i] ); + m_index++; + } + } } public void rewind() { - m_ms.Seek( 0, SeekOrigin.Begin ); - } - - public void writeLine( string s ) { - byte[] buff = m_enc.GetBytes( s + Environment.NewLine ); - m_ms.Write( buff, 0, buff.Length ); - } - - public void close() { - if ( m_ms != null ) { - m_ms.Close(); - } - } - - public int peek() { - long current = m_ms.Position; - int ret = m_ms.ReadByte(); - m_ms.Seek( current, SeekOrigin.Begin ); - return ret; + m_index = 0; } public string readLine() { - List buffer = new List(); - byte value; - int ret; - ret = m_ms.ReadByte(); - while ( ret >= 0 ) { - value = (byte)ret; - if ( value == NEW_LINE[0] ) { - byte next; - long current = m_ms.Position; //0x0Dを検出した直後のストリームの位置 - for ( int i = 1; i < NEW_LINE.Length; i++ ) { - ret = m_ms.ReadByte(); - if ( ret >= 0 ) { - next = (byte)ret; - if ( next != NEW_LINE[i] ) { - m_ms.Seek( current, SeekOrigin.Begin ); - break; - } - } - } - break; + m_index++; + return m_lines[m_index - 1]; + } + + public int peek() { + if ( m_index < m_lines.Count ) { + if ( m_lines[m_index] == "" ) { + return -1; + } else { + return (int)m_lines[m_index][0]; } - buffer.Add( value ); - ret = m_ms.ReadByte(); + } else { + return -1; } - return Encoding.Unicode.GetString( buffer.ToArray() ); + } + + public void close() { + m_lines.Clear(); } public void Dispose() { - if ( m_ms != null ) { - m_ms.Close(); - } - } - - public TextMemoryStream( string path, Encoding encode ) { - m_access = FileAccess.Read; - m_ms = new MemoryStream(); - m_enc = encode; - if ( File.Exists( path ) ) { - using ( StreamReader sr = new StreamReader( path, encode ) ) { - while ( sr.Peek() >= 0 ) { - string line = sr.ReadLine(); - byte[] buffer = m_enc.GetBytes( line + Environment.NewLine ); - m_ms.Write( buffer, 0, buffer.Length ); - } - } - m_ms.Seek( 0, SeekOrigin.Begin ); - } - NEW_LINE = m_enc.GetBytes( Environment.NewLine ); - } - - public TextMemoryStream( FileAccess access ) { - m_access = access; - m_ms = new MemoryStream(); - m_enc = Encoding.Unicode; - NEW_LINE = m_enc.GetBytes( Environment.NewLine ); - } - - public TextMemoryStream() { - m_access = FileAccess.Write; - m_ms = new MemoryStream(); - m_enc = Encoding.Unicode; - NEW_LINE = m_enc.GetBytes( Environment.NewLine ); + close(); } } diff --git a/trunk/Boare.Lib.Vsq/TransCodeUtil.cs b/trunk/Boare.Lib.Vsq/TransCodeUtil.cs new file mode 100644 index 0000000..f0dbf2a --- /dev/null +++ b/trunk/Boare.Lib.Vsq/TransCodeUtil.cs @@ -0,0 +1,32 @@ +namespace Boare.Lib.Vsq { + + public static class TransCodeUtil { + private static readonly byte[] MAP_L = new byte[] { 0xA, 0xB, 0x8, 0x9, 0xE, 0xF, 0xC, 0xD, 0x2, 0x3, 0x0, 0x1, 0x6, 0x7, 0x4, 0x5 }; + private static readonly byte[] MAP_R = new byte[] { 0x1, 0x0, 0x3, 0x2, 0x5, 0x4, 0x7, 0x6, 0x9, 0x8, 0xB, 0xA, 0xD, 0xC, 0xF, 0xE }; + + public static void decodeBytes( ref byte[] dat ) { + for ( int i = 0; i < dat.Length; i++ ) { + byte M = (byte)(dat[i] >> 4); + byte L = (byte)(dat[i] - (M << 4)); + byte newM = endecode_vvd_m( M ); + byte newL = endecode_vvd_l( L ); + dat[i] = (byte)((newM << 4) | newL); + } + for ( int i = 0; i < dat.Length - 1; i++ ) { + if ( dat[i] == 0x17 && dat[i + 1] == 0x10 ) { + dat[i] = 0x0d; + dat[i + 1] = 0x0a; + } + } + } + + static byte endecode_vvd_l( byte value ) { + return MAP_L[value]; + } + + static byte endecode_vvd_m( byte value ) { + return MAP_R[value]; + } + } + +} \ No newline at end of file diff --git a/trunk/Boare.Lib.Vsq/UstEnvelope.cs b/trunk/Boare.Lib.Vsq/UstEnvelope.cs new file mode 100644 index 0000000..b864160 --- /dev/null +++ b/trunk/Boare.Lib.Vsq/UstEnvelope.cs @@ -0,0 +1,78 @@ +/* + * UstEnvelope.cs + * Copyright (c) 2009 kbinani + * + * This file is part of Boare.Lib.Vsq. + * + * Boare.Lib.Vsq is free software; you can redistribute it and/or + * modify it under the terms of the BSD License. + * + * Boare.Lib.Vsq 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. + */ +using System; + +namespace Boare.Lib.Vsq { + + [Serializable] + public class UstEnvelope : ICloneable { + public int p1 = 0; + public int p2 = 5; + public int p3 = 35; + public int v1 = 0; + public int v2 = 100; + public int v3 = 100; + public int v4 = 0; + //public string Separator = ""; + public int p4 = 0; + public int p5 = 0; + public int v5 = 100; + + public UstEnvelope() { + } + + public UstEnvelope( string line ) { + if ( line.ToLower().StartsWith( "envelope=" ) ) { + string[] spl = line.Split( '=' ); + spl = spl[1].Split( ',' ); + if ( spl.Length < 7 ) { + return; + } + //Separator = ""; + p1 = int.Parse( spl[0] ); + p2 = int.Parse( spl[1] ); + p3 = int.Parse( spl[2] ); + v1 = int.Parse( spl[3] ); + v2 = int.Parse( spl[4] ); + v3 = int.Parse( spl[5] ); + v4 = int.Parse( spl[6] ); + if ( spl.Length == 11 ) { + //Separator = "%"; + p4 = int.Parse( spl[8] ); + p5 = int.Parse( spl[9] ); + v5 = int.Parse( spl[10] ); + } + } + } + + public object Clone() { + return new UstEnvelope( ToString() ); + } + + public override string ToString() { + string ret = "Envelope=" + p1 + "," + p2 + "," + p3 + "," + v1 + "," + v2 + "," + v3 + "," + v4; + ret += ",%," + p4 + "," + p5 + "," + v5; + return ret; + } + + public int getCount() { + //if ( Separator == "%" ) { + return 5; + //} else { + //return 4; + //} + } + } + +} \ No newline at end of file diff --git a/trunk/Boare.Lib.Vsq/UstPortamento.cs b/trunk/Boare.Lib.Vsq/UstPortamento.cs new file mode 100644 index 0000000..4b1931b --- /dev/null +++ b/trunk/Boare.Lib.Vsq/UstPortamento.cs @@ -0,0 +1,151 @@ +/* + * UstPortamento.cs + * Copyright (c) 2009 kbinani + * + * This file is part of Boare.Lib.Vsq. + * + * Boare.Lib.Vsq is free software; you can redistribute it and/or + * modify it under the terms of the BSD License. + * + * Boare.Lib.Vsq 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. + */ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Boare.Lib.Vsq { + + [Serializable] + public class UstPortamento : ICloneable { + public List Points = new List(); + public int Start; + + public void print( StreamWriter sw ) { + string pbw = ""; + string pby = ""; + string pbm = ""; + for ( int i = 0; i < Points.Count; i++ ) { + string comma = (i == 0 ? "" : ","); + pbw += comma + Points[i].Step; + pby += comma + Points[i].Value; + string type = ""; + switch ( Points[i].Type ) { + case UstPortamentoType.S: + type = ""; + break; + case UstPortamentoType.Linear: + type = "s"; + break; + case UstPortamentoType.R: + type = "r"; + break; + case UstPortamentoType.J: + type = "j"; + break; + } + pbm += comma + type; + } + sw.WriteLine( "PBW=" + pbw ); + sw.WriteLine( "PBS=" + Start ); + sw.WriteLine( "PBY=" + pby ); + sw.WriteLine( "PBM=" + pbm ); + } + + public object Clone() { + UstPortamento ret = new UstPortamento(); + for ( int i = 0; i < Points.Count; i++ ) { + ret.Points.Add( Points[i] ); + } + ret.Start = Start; + return ret; + } + + /* + PBW=50,50,46,48,56,50,50,50,50 + PBS=-87 + PBY=-15.9,-20,-31.5,-26.6 + PBM=,s,r,j,s,s,s,s,s + */ + public void ParseLine( string line ) { + line = line.ToLower(); + string[] spl = line.Split( '=' ); + if ( spl.Length == 0 ) { + return; + } + string[] values = spl[1].Split( ',' ); + if ( line.StartsWith( "pbs=" ) ) { + Start = int.Parse( values[0] ); + } else if ( line.StartsWith( "pbw=" ) ) { + for ( int i = 0; i < values.Length; i++ ) { + if ( i >= Points.Count ) { + Points.Add( new UstPortamentoPoint() ); + } + UstPortamentoPoint up = Points[i]; + up.Step = int.Parse( values[i] ); + Points[i] = up; + } + } else if ( line.StartsWith( "pby=" ) ) { + for ( int i = 0; i < values.Length; i++ ) { + if ( i >= Points.Count ) { + Points.Add( new UstPortamentoPoint() ); + } + UstPortamentoPoint up = Points[i]; + up.Value = float.Parse( values[i] ); + Points[i] = up; + } + } else if ( line.StartsWith( "pbm=" ) ) { + for ( int i = 0; i < values.Length; i++ ) { + if ( i >= Points.Count ) { + Points.Add( new UstPortamentoPoint() ); + } + UstPortamentoPoint up = Points[i]; + switch ( values[i].ToLower() ) { + case "s": + up.Type = UstPortamentoType.Linear; + break; + case "r": + up.Type = UstPortamentoType.R; + break; + case "j": + up.Type = UstPortamentoType.J; + break; + default: + up.Type = UstPortamentoType.S; + break; + } + Points[i] = up; + } + } else if ( line.StartsWith( "pbs=" ) ) { + + } + } + } + + public struct UstPortamentoPoint { + public int Step; + public float Value; + public UstPortamentoType Type; + } + + public enum UstPortamentoType{ + /// + /// S型.表記は''(空文字) + /// + S, + /// + /// 直線型.表記は's' + /// + Linear, + /// + /// R型.表記は'r' + /// + R, + /// + /// J型.表記は'j' + /// + J, + } + +} diff --git a/trunk/Boare.Lib.Vsq/UstVibrato.cs b/trunk/Boare.Lib.Vsq/UstVibrato.cs new file mode 100644 index 0000000..20bc327 --- /dev/null +++ b/trunk/Boare.Lib.Vsq/UstVibrato.cs @@ -0,0 +1,89 @@ +/* + * UstVibrato.cs + * Copyright (c) 2009 kbinani + * + * This file is part of Boare.Lib.Vsq. + * + * Boare.Lib.Vsq is free software; you can redistribute it and/or + * modify it under the terms of the BSD License. + * + * Boare.Lib.Vsq 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. + */ +using System; + +namespace Boare.Lib.Vsq { + + [Serializable] + public class UstVibrato : ICloneable { + /// + /// 音符の長さに対する、パーセントで表したビブラートの長さ。 + /// + public float Length; + /// + /// ミリセカンドで表したビブラートによるピッチ振動の周期 + /// + public float Period; + /// + /// Centで表した、ビブラートによるピッチ振動の振幅。Peak to Peakは2*Depthとなる。 + /// + public float Depth; + /// + /// ビブラート長さに対する、パーセントで表したピッチ振動のフェードインの長さ。 + /// + public float In; + /// + /// ビブラートの長さに対するパーセントで表したピッチ振動のフェードアウトの長さ。 + /// + public float Out; + /// + /// ピッチ振動開始時の位相。2PIに対するパーセントで表す。 + /// + public float Phase; + /// + /// ピッチ振動の中心値と、音符の本来の音の高さからのずれ。Depthに対するパーセントで表す。 + /// + public float Shift; + public float Unknown = 100; + + public UstVibrato( string line ) { + if ( line.ToLower().StartsWith( "vbr=" ) ) { + string[] spl = line.Split( '=' ); + spl = spl[1].Split( ',' ); + //VBR=65,180,70,20.0,17.6,82.8,49.8,100 + if ( spl.Length >= 8 ) { + Length = float.Parse( spl[0] ); + Period = float.Parse( spl[1] ); + Depth = float.Parse( spl[2] ); + In = float.Parse( spl[3] ); + Out = float.Parse( spl[4] ); + Phase = float.Parse( spl[5] ); + Shift = float.Parse( spl[6] ); + Unknown = float.Parse( spl[7] ); + } + } + } + + public UstVibrato() { + } + + public override string ToString() { + return "VBR=" + Length + "," + Period + "," + Depth + "," + In + "," + Out + "," + Phase + "," + Shift + "," + Unknown; + } + + public object Clone() { + UstVibrato ret = new UstVibrato(); + ret.Length = Length; + ret.Period = Period; + ret.Depth = Depth; + ret.In = In; + ret.Out = Out; + ret.Phase = Phase; + ret.Shift = Shift; + ret.Unknown = Unknown; + return ret; + } + } + +} diff --git a/trunk/Boare.Lib.Vsq/VibratoConfig.cs b/trunk/Boare.Lib.Vsq/VibratoConfig.cs new file mode 100644 index 0000000..d1152e4 --- /dev/null +++ b/trunk/Boare.Lib.Vsq/VibratoConfig.cs @@ -0,0 +1,132 @@ +/* + * VibratoConfig.cs + * Copyright (c) 2009 kbinani + * + * This file is part of Boare.Lib.Vsq. + * + * Boare.Lib.Vsq is free software; you can redistribute it and/or + * modify it under the terms of the BSD License. + * + * Boare.Lib.Vsq 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. + */ +using System; +using System.IO; + +namespace Boare.Lib.Vsq { + + public class VibratoConfig { + public int number; + public String file; + public String author; + public String vendor; + public VibratoHandle contents; + + public VibratoConfig() { + contents = new VibratoHandle(); + } + + public void parseAic( String aic_file ) { + using ( StreamReader sr = new StreamReader( aic_file ) ) { + String line; + String current_entry = ""; + String articulation = ""; + String depth_bpx = ""; + String depth_bpy = ""; + String rate_bpx = ""; + String rate_bpy = ""; + int depth_bpnum = 0; + int rate_bpnum = 0; + while ( (line = sr.ReadLine()) != null ) { + if ( line.StartsWith( "[" ) ) { + current_entry = line; + continue; + } else if ( line == "" || line.StartsWith( ";" ) ) { + continue; + } + + String[] spl = line.Split( new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries ); + if ( spl.Length < 2 ) { + continue; + } + spl[0] = spl[0].Trim(); + spl[1] = spl[1].Trim(); + if ( current_entry == "[Common]" ) { + if ( spl[0] == "Articulation" ) { + articulation = spl[1]; + } + } else if ( current_entry == "[Parameter]" ) { + if ( spl[0] == "Length" ) { + try { + this.contents.Length = int.Parse( spl[1] ); + } catch { } + } else if ( spl[0] == "StartDepth" ) { + try { + this.contents.StartDepth = int.Parse( spl[1] ); + } catch { } + } else if ( spl[0] == "DepthBPNum" ) { + try { + depth_bpnum = int.Parse( spl[1] ); + } catch { } + } else if ( spl[0] == "DepthBPX" ) { + depth_bpx = spl[1]; + } else if ( spl[0] == "DepthBPY" ) { + depth_bpy = spl[1]; + } else if ( spl[0] == "StartRate" ) { + try { + this.contents.StartRate = int.Parse( spl[1] ); + } catch { } + } else if ( spl[0] == "RateBPNum" ) { + try { + rate_bpnum = int.Parse( spl[1] ); + } catch { } + } else if ( spl[0] == "RateBPX" ) { + rate_bpx = spl[1]; + } else if ( spl[0] == "RateBPY" ) { + rate_bpy = spl[1]; + } + } + } + if ( articulation != "Vibrato" ) { + return; + } + + // depth bp + if ( depth_bpnum > 0 && depth_bpx != "" && depth_bpy != "" ) { + String[] bpx = depth_bpx.Split( ',' ); + String[] bpy = depth_bpy.Split( ',' ); + if ( depth_bpnum == bpx.Length && depth_bpnum == bpy.Length ) { + float[] x = new float[depth_bpnum]; + int[] y = new int[depth_bpnum]; + try { + for ( int i = 0; i < depth_bpnum; i++ ) { + x[i] = float.Parse( bpx[i] ); + y[i] = int.Parse( bpy[i] ); + } + this.contents.DepthBP = new VibratoBPList( x, y ); + } catch { } + } + } + + // rate bp + if ( rate_bpnum > 0 && rate_bpx != "" && rate_bpy != "" ) { + String[] bpx = rate_bpx.Split( ',' ); + String[] bpy = rate_bpy.Split( ',' ); + if ( rate_bpnum == bpx.Length && rate_bpnum == bpy.Length ) { + float[] x = new float[rate_bpnum]; + int[] y = new int[rate_bpnum]; + try { + for ( int i = 0; i < rate_bpnum; i++ ) { + x[i] = float.Parse( bpx[i] ); + y[i] = int.Parse( bpy[i] ); + } + this.contents.RateBP = new VibratoBPList( x, y ); + } catch { } + } + } + } + } + } + +} diff --git a/trunk/Boare.Lib.Vsq/VibratoType.cs b/trunk/Boare.Lib.Vsq/VibratoType.cs index 58953cc..925f7bb 100644 --- a/trunk/Boare.Lib.Vsq/VibratoType.cs +++ b/trunk/Boare.Lib.Vsq/VibratoType.cs @@ -100,9 +100,9 @@ namespace Boare.Lib.Vsq { return VibratoType.NormalType1; case "$04040002": return VibratoType.NormalType2; - case "$04040003": + case "$04040003": return VibratoType.NormalType3; - case "$0400004": + case "$04040004": return VibratoType.NormalType4; case "$04040005": return VibratoType.ExtremeType1; @@ -146,7 +146,7 @@ namespace Boare.Lib.Vsq { case VibratoType.NormalType3: return "$04040003"; case VibratoType.NormalType4: - return "$0400004"; + return "$04040004"; case VibratoType.ExtremeType1: return "$04040005"; case VibratoType.ExtremeType2: diff --git a/trunk/Boare.Lib.Vsq/VocaloSysUtil.cs b/trunk/Boare.Lib.Vsq/VocaloSysUtil.cs new file mode 100644 index 0000000..d151176 --- /dev/null +++ b/trunk/Boare.Lib.Vsq/VocaloSysUtil.cs @@ -0,0 +1,791 @@ +/* + * VocaloSysUtil.s + * Copyright (c) 2009 kbinani + * + * This file is part of Boare.Lib.Vsq. + * + * Boare.Lib.Vsq is free software; you can redistribute it and/or + * modify it under the terms of the BSD License. + * + * Boare.Lib.Vsq 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. + */ +using System; +using System.IO; +using System.Collections.Generic; +using Microsoft.Win32; + +namespace Boare.Lib.Vsq { + + using boolean = Boolean; + + public static class VocaloSysUtil{ + private static SingerConfigSys s_singer_config_sys1; + private static SingerConfigSys s_singer_config_sys2; + private static ExpressionConfigSys s_exp_config_sys1; + private static ExpressionConfigSys s_exp_config_sys2; + private static String s_path_vsti1; + private static String s_path_vsti2; + private static String s_path_editor1; + private static String s_path_editor2; + + static VocaloSysUtil() { + Vector dir1 = new Vector(); + RegistryKey key1 = Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID", false ); + String header1 = "HKLM\\SOFTWARE\\VOCALOID"; + print( key1, header1, dir1 ); + key1.Close(); + String path_voicedb1; + String path_expdb1; + Vector installed_singers1 = new Vector(); + extract( dir1, + header1, + out s_path_vsti1, + out path_voicedb1, + out path_expdb1, + out s_path_editor1, + installed_singers1 ); + s_singer_config_sys1 = new SingerConfigSys( path_voicedb1, installed_singers1.ToArray() ); + s_exp_config_sys1 = new ExpressionConfigSys( path_expdb1 ); + + Vector dir2 = new Vector(); + RegistryKey key2 = Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID2", false ); + String header2 = "HKLM\\SOFTWARE\\VOCALOID2"; + print( key2, header2 , dir2 ); + key2.Close(); + String path_voicedb2; + String path_expdb2; + Vector installed_singers2 = new Vector(); + extract( dir2, + header2, + out s_path_vsti2, + out path_voicedb2, + out path_expdb2, + out s_path_editor2, + installed_singers2 ); + s_singer_config_sys2 = new SingerConfigSys( path_voicedb2, installed_singers2.ToArray() ); + s_exp_config_sys2 = new ExpressionConfigSys( path_expdb2 ); + } + + private static void extract( Vector dir, + String header, + out String path_vsti, + out String path_voicedb, + out String path_expdb, + out String path_editor, + Vector installed_singers ) { + Vector application = new Vector(); + Vector expression = new Vector(); + Vector voice = new Vector(); + path_vsti = ""; + path_expdb = ""; + path_voicedb = ""; + path_editor = ""; + foreach ( String s in dir ) { + if ( s.StartsWith( header + "\\APPLICATION" ) ) { + application.Add( s.Substring( (header + "\\APPLICATION").Length ) ); + } else if ( s.StartsWith( header + "\\DATABASE\\EXPRESSION" ) ) { + expression.Add( s.Substring( (header + "\\DATABASE\\EXPRESSION").Length ) ); + } else if ( s.StartsWith( header + "\\DATABASE\\VOICE" ) ) { + voice.Add( s.Substring( (header + "\\DATABASE\\VOICE\\").Length ) ); + } + } + + // path_vstiを取得 + foreach ( String s in application ) { + String[] spl = s.Split( '\t' ); + if ( spl.Length >= 3 && spl[1].Equals( "PATH" ) ){ + if ( spl[2].ToLower().EndsWith( ".dll" ) ) { + path_vsti = spl[2]; + } else if ( spl[2].ToLower().EndsWith( ".exe" ) ) { + path_editor = spl[2]; + } + } + } + + // path_vicedbを取得 + Vector voice_ids = new Vector(); + // 最初はpath_voicedbの取得と、id(BHXXXXXXXXXXXXXXXX)のようなシリアルを取得 + foreach ( String s in voice ) { + String[] spl = s.Split( '\t' ); + if ( spl.Length >= 2 ) { + if ( spl[0].Equals( "VOICEDIR" ) ) { + path_voicedb = spl[1]; + } else if ( spl.Length >= 3 ) { + String[] spl2 = spl[0].Split( '\\' ); + if ( spl2.Length == 1 ) { + if ( !voice_ids.Contains( spl2[0] ) ) { + voice_ids.Add( spl2[0] ); + } + } + } + } + } + // 取得したシリアルを元に、installed_singersを取得 + foreach ( String s in voice_ids ) { + String install_dir = ""; + foreach ( String s2 in voice ) { + if ( s2.StartsWith( header + "\\" + s + "\t" ) ) { + String[] spl = s2.Split( '\t' ); + if ( spl.Length >= 3 && spl[1].Equals( "INSTALLDIR" ) ) { + install_dir = Path.Combine( spl[2], s ); + break; + } + } + } + if ( install_dir.Equals( "" ) ) { + install_dir = Path.Combine( path_voicedb, s ); + } + installed_singers.Add( install_dir ); + } + + // path_expdbを取得 + Vector exp_ids = new Vector(); + // 最初はpath_expdbの取得と、id(BHXXXXXXXXXXXXXXXX)のようなシリアルを取得 + foreach ( String s in expression ) { + String[] spl = s.Split( '\t' ); + if ( spl.Length >= 2 ) { + if ( spl[0].Equals( "EXPRESSIONDIR" ) ) { + path_expdb = spl[1]; + } else if ( spl.Length >= 3 ) { + String[] spl2 = spl[0].Split( '\\' ); + if ( spl2.Length == 1 ) { + if ( !exp_ids.Contains( spl2[0] ) ) { + exp_ids.Add( spl2[0] ); + } + } + } + } + } + // 取得したシリアルを元に、installed_singersを取得 + /*foreach ( String s in exp_ids ) { + String install_dir = ""; + foreach ( String s2 in expression ) { + if ( s2.StartsWith( header + "\\" + s + "\t" ) ) { + String[] spl = s2.Split( '\t' ); + if ( spl.Length >= 3 && spl[1].Equals( "INSTALLDIR" ) ) { + install_dir = Path.Combine( spl[2], s ); + break; + } + } + } + if ( install_dir.Equals( "" ) ) { + install_dir = Path.Combine( path_expdb, s ); + } + installed_singers.Add( install_dir ); + }*/ + +#if DEBUG + Console.WriteLine( "path_vsti=" + path_vsti ); + Console.WriteLine( "path_voicedb=" + path_voicedb ); + Console.WriteLine( "path_expdb=" + path_expdb ); + Console.WriteLine( "installed_singers=" ); + foreach ( String s in installed_singers ) { + Console.WriteLine( " " + s ); + } +#endif + } + + // レジストリkey内の値を再帰的に検索し、ファイルfpに順次出力する + private static void print( RegistryKey key, String parent_name, Vector list ){ + // 直下のキー内を再帰的にリストアップ + String[] subkeys = key.GetSubKeyNames(); + foreach( String s in subkeys ){ + RegistryKey subkey = key.OpenSubKey( s, false ); + print( subkey, parent_name + "\\" + s, list ); + subkey.Close(); + } + + // 直下の値を出力 + String[] valuenames = key.GetValueNames(); + foreach( String s in valuenames ){ + RegistryValueKind kind = key.GetValueKind( s ); + if ( kind == RegistryValueKind.String ){ + String str = parent_name + "\t" + s + "\t" + (String)key.GetValue( s ); + list.Add( str ); + } + } + } + + /// + /// Gets the name of original singer of specified program change. + /// + /// + /// + public static String getOriginalSinger1( String singer ) { + string voiceidstr = ""; + SingerConfig[] singer_configs = s_singer_config_sys1.getSingerConfigs(); + for ( int i = 0; i < singer_configs.Length; i++ ) { + if ( singer.Equals( singer_configs[i].VOICENAME ) ) { + voiceidstr = singer_configs[i].VOICEIDSTR; + break; + } + } + if ( voiceidstr.Equals( "" ) ) { + return ""; + } + SingerConfig[] installed_singers = s_singer_config_sys1.getInstalledSingers(); + for ( int i = 0; i < installed_singers.Length; i++ ) { + if ( voiceidstr.Equals( installed_singers[i].VOICEIDSTR ) ) { + return installed_singers[i].VOICENAME; + } + } + return ""; + } + + /// + /// Gets the name of original singer of specified program change. + /// + /// + /// + public static String getOriginalSinger2( String singer ) { + string voiceidstr = ""; + SingerConfig[] singer_configs = s_singer_config_sys2.getSingerConfigs(); + for ( int i = 0; i < singer_configs.Length; i++ ) { + if ( singer.Equals( singer_configs[i].VOICENAME ) ) { + voiceidstr = singer_configs[i].VOICEIDSTR; + break; + } + } + if ( voiceidstr.Equals( "" ) ) { + return ""; + } + SingerConfig[] installed_singers = s_singer_config_sys2.getInstalledSingers(); + for ( int i = 0; i < installed_singers.Length; i++ ) { + if ( voiceidstr.Equals( installed_singers[i].VOICEIDSTR ) ) { + return installed_singers[i].VOICENAME; + } + } + return ""; + } + + public static VsqID getSingerID1( String singer ) { + return s_singer_config_sys1.getSingerID( singer ); + } + + public static VsqID getSingerID2( String singer ) { + return s_singer_config_sys2.getSingerID( singer ); + } + + public static String getEditorPath1() { + return s_path_editor1; + } + + public static String getEditorPath2() { + return s_path_editor2; + } + + public static String getDllPathVsti1() { + return s_path_vsti1; + } + + public static String getDllPathVsti2() { + return s_path_vsti2; + } + + public static SingerConfig[] getSingerConfigs1() { + return s_singer_config_sys1.getSingerConfigs(); + } + + public static SingerConfig[] getSingerConfigs2() { + return s_singer_config_sys2.getSingerConfigs(); + } + + /// + /// Gets the voice language of specified program change + /// + /// name of singer + /// + public static VsqVoiceLanguage getLanguageFromName( string name ) { + switch ( name.ToLower() ) { + case "meiko": + case "kaito": + case "miku": + case "rin": + case "len": + case "rin_act2": + case "len_act2": + case "gackpoid": + case "luka_jpn": + case "megpoid": + return VsqVoiceLanguage.Japanese; + case "sweet_ann": + case "prima": + case "luka_eng": + case "sonika": + return VsqVoiceLanguage.English; + } + return VsqVoiceLanguage.Default; + } + + public static double getAmplifyCoeffFromPanLeft( int pan ) { + return pan / -64.0 + 1.0; + } + + public static double getAmplifyCoeffFromPanRight( int pan ) { + return pan / 64.0 + 1.0; + } + + public static double getAmplifyCoeffFromFeder( int feder ) { + return Math.Exp( -1.26697245e-02 + 1.18448420e-01 * feder / 10.0 ); + } + + /// + /// Transform the byte array(length=8) to unsigned long, assuming that the byte array is little endian. + /// + /// + /// + public static ulong makelong_le( byte[] oct ) { + return (ulong)oct[7] << 56 | (ulong)oct[6] << 48 | (ulong)oct[5] << 40 | (ulong)oct[4] << 32 | (ulong)oct[3] << 24 | (ulong)oct[2] << 16 | (ulong)oct[1] << 8 | (ulong)oct[0]; + } + } + + public static class VocaloSysUtil_ { + private static bool s_initialized = false; + + private static string s_dll_path2 = ""; + private static string s_editor_path2 = ""; + private static string s_voicedbdir2 = ""; + private static List s_installed_singers2 = new List(); + private static List s_singer_configs2 = new List(); + + private static string s_dll_path1 = ""; + private static string s_editor_path1 = ""; + private static string s_voicedbdir1 = ""; + private static List s_installed_singers1 = new List(); + private static List s_singer_configs1 = new List(); + + private const int MAX_SINGERS = 0x4000; + + static VocaloSysUtil_() { + init_vocalo2(); + init_vocalo1(); + } + + /// + /// Gets the name of original singer of specified program change. + /// + /// + /// + public static string getOriginalSinger1( string singer ) { + string voiceidstr = ""; + for ( int i = 0; i < s_singer_configs1.Count; i++ ) { + if ( singer == s_singer_configs1[i].VOICENAME ) { + voiceidstr = s_singer_configs1[i].VOICEIDSTR; + } + } + if ( voiceidstr == "" ) { + return ""; + } + for ( int i = 0; i < s_installed_singers1.Count; i++ ) { + if ( voiceidstr == s_installed_singers1[i].VOICEIDSTR ) { + return s_installed_singers1[i].VOICENAME; + } + } + return ""; + } + + /// + /// Gets the name of original singer of specified program change. + /// + /// + /// + public static string getOriginalSinger2( string singer ) { + string voiceidstr = ""; + for ( int i = 0; i < s_singer_configs2.Count; i++ ) { + if ( singer == s_singer_configs2[i].VOICENAME ) { + voiceidstr = s_singer_configs2[i].VOICEIDSTR; + } + } + if ( voiceidstr == "" ) { + return ""; + } + for ( int i = 0; i < s_installed_singers2.Count; i++ ) { + if ( voiceidstr == s_installed_singers2[i].VOICEIDSTR ) { + return s_installed_singers2[i].VOICENAME; + } + } + return ""; + } + + /// + /// Gets the voice language of specified program change + /// + /// name of singer + /// + public static VsqVoiceLanguage getLanguageFromName( string name ) { + switch ( name ) { + case "MEIKO": + case "KAITO": + case "Miku": + case "Rin": + case "Len": + case "Rin_ACT2": + case "Len_ACT2": + case "Gackpoid": + case "Luka_JPN": + case "Megpoid": + return VsqVoiceLanguage.Japanese; + case "Sweet_Ann": + case "Prima": + case "Luka_ENG": + return VsqVoiceLanguage.English; + } + return VsqVoiceLanguage.Default; + } + + public static VsqID getSingerID1( string singer_name ) { + VsqID ret = new VsqID( 0 ); + ret.type = VsqIDType.Singer; + SingerConfig sc = null; + for ( int i = 0; i < s_singer_configs1.Count; i++ ) { + if ( s_singer_configs1[i].VOICENAME == singer_name ) { + sc = s_singer_configs1[i]; + break; + } + } + if ( sc == null ) { + sc = new SingerConfig(); + } + int lang = 0; + foreach ( SingerConfig sc2 in s_installed_singers1 ) { + if ( sc.VOICEIDSTR == sc2.VOICEIDSTR ) { + lang = (int)getLanguageFromName( sc.VOICENAME ); + break; + } + } + ret.IconHandle = new IconHandle(); + ret.IconHandle.IconID = "$0701" + sc.Program.ToString( "0000" ); + ret.IconHandle.IDS = sc.VOICENAME; + ret.IconHandle.Index = 0; + ret.IconHandle.Language = lang; + ret.IconHandle.Length = 1; + ret.IconHandle.Original = sc.Original; + ret.IconHandle.Program = sc.Program; + ret.IconHandle.Caption = ""; + return ret; + } + + public static VsqID getSingerID2( string singer_name ) { + VsqID ret = new VsqID( 0 ); + ret.type = VsqIDType.Singer; + SingerConfig sc = null; + for ( int i = 0; i < s_singer_configs2.Count; i++ ) { + if ( s_singer_configs2[i].VOICENAME == singer_name ) { + sc = s_singer_configs2[i]; + break; + } + } + if ( sc == null ) { + sc = new SingerConfig(); + } + int lang = 0; + foreach ( SingerConfig sc2 in s_installed_singers2 ) { + if ( sc.VOICEIDSTR == sc2.VOICEIDSTR ) { + lang = (int)getLanguageFromName( sc.VOICENAME ); + break; + } + } + ret.IconHandle = new IconHandle(); + ret.IconHandle.IconID = "$0701" + sc.Program.ToString( "0000" ); + ret.IconHandle.IDS = sc.VOICENAME; + ret.IconHandle.Index = 0; + ret.IconHandle.Language = lang; + ret.IconHandle.Length = 1; + ret.IconHandle.Original = sc.Original; + ret.IconHandle.Program = sc.Program; + ret.IconHandle.Caption = ""; + return ret; + } + + public static SingerConfig[] getSingerConfigs1() { + return s_singer_configs1.ToArray(); + } + + public static SingerConfig[] getSingerConfigs2() { + return s_singer_configs2.ToArray(); + } + + public static double getAmplifyCoeffFromPanLeft( int pan ) { + return pan / -64.0 + 1.0; + } + + public static double getAmplifyCoeffFromPanRight( int pan ) { + return pan / 64.0 + 1.0; + } + + public static double getAmplifyCoeffFromFeder( int feder ) { + return Math.Exp( -1.26697245e-02 + 1.18448420e-01 * feder / 10.0 ); + } + + public static string getEditorPath2() { + return s_editor_path2; + } + + public static string getEditorPath1() { + return s_editor_path1; + } + + public static string getDllPathVsti2() { + return s_dll_path2; + } + + public static string getDllPathVsti1() { + return s_dll_path1; + } + + /// + /// VOCALOID1システムのプロパティを取得 + /// + private static void init_vocalo1() { + // vocaloid1 dll path + RegistryKey v1application = null; + v1application = Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID\\APPLICATION", false ); + if ( v1application != null ) { + string[] keys = v1application.GetSubKeyNames(); + for ( int i = 0; i < keys.Length; i++ ) { + RegistryKey key = v1application.OpenSubKey( keys[i], false ); + if ( key != null ) { + string name = (string)key.GetValue( "PATH" ); + if ( name.ToLower().EndsWith( "\\vocaloid.dll" ) ) { + s_dll_path1 = name; + } else if ( name.ToLower().EndsWith( "\\vocaloid.exe" ) ) { + s_editor_path1 = name; + } + key.Close(); + } + } + v1application.Close(); + } + + // voicedbdir for vocaloid1 + RegistryKey v1database = Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID\\DATABASE\\VOICE", false ); + if ( v1database != null ) { + s_voicedbdir1 = (string)v1database.GetValue( "VOICEDIR", "" ); +#if DEBUG + Console.WriteLine( "s_voicedbdir1=" + s_voicedbdir1 ); +#endif + // インストールされている歌手のVOICEIDSTRを列挙 + string[] singer_voiceidstrs = v1database.GetSubKeyNames(); + List vvoice_keys = new List(); + List vvoice_values = new List(); + foreach ( string voiceidstr in singer_voiceidstrs ) { + RegistryKey singer = v1database.OpenSubKey( voiceidstr ); + if ( singer == null ) { + continue; + } + RegistryKey vvoice = singer.OpenSubKey( "vvoice" ); + if ( vvoice != null ) { + string[] vvoices = vvoice.GetValueNames(); + + // インストールされた歌手の.vvdを読みにいく + // installdir以下の、拡張子.vvdのファイルを探す + foreach ( string file in Directory.GetFiles( Path.Combine( s_voicedbdir1, voiceidstr ), "*.vvd" ) ) { + SingerConfig config = SingerConfig.fromVvd( file, 0 ); //とりあえずプログラムチェンジは0 + s_installed_singers1.Add( config ); + } + + // vvoice*.vvdを読みにいく。 + foreach ( string s in vvoices ) { +#if DEBUG + Console.WriteLine( "s=" + s ); +#endif + string file = Path.Combine( s_voicedbdir1, s + ".vvd" ); + if ( File.Exists( file ) ) { + SingerConfig config = SingerConfig.fromVvd( file, 0 ); + vvoice_keys.Add( s ); + vvoice_values.Add( config ); + } + } + } + singer.Close(); + } + + // voice.mapを読み込んで、s_singer_configs1のプログラムチェンジを更新する + string map = Path.Combine( s_voicedbdir1, "voice.map" ); + if ( File.Exists( map ) ) { + using ( FileStream fs = new FileStream( map, FileMode.Open, FileAccess.Read ) ) { + byte[] dat = new byte[8]; + fs.Seek( 0x20, SeekOrigin.Begin ); + for ( int i = 0; i < MAX_SINGERS; i++ ) { + fs.Read( dat, 0, 8 ); + ulong value = makelong_le( dat ); + if ( value >= 1 ) { +#if DEBUG + Console.WriteLine( "value=" + value ); +#endif + for ( int j = 0; j < vvoice_keys.Count; j++ ) { + if ( vvoice_keys[j] == "vvoice" + value ) { + vvoice_values[j].Program = i; + } + } + } + } + } + } + + // s_installed_singers1のSingerConfigのProgramとOriginalを適当に頒番する + for ( int i = 0; i < s_installed_singers1.Count; i++ ) { + s_installed_singers1[i].Program = i; + s_installed_singers1[i].Original = i; + } + + // s_singer_configs1を更新 + for ( int i = 0; i < vvoice_values.Count; i++ ) { + for ( int j = 0; j < s_installed_singers1.Count; j++ ) { + if ( vvoice_values[i].VOICEIDSTR == s_installed_singers1[j].VOICEIDSTR ) { + vvoice_values[i].Original = s_installed_singers1[j].Program; + break; + } + } + s_singer_configs1.Add( vvoice_values[i] ); + } + v1database.Close(); + } +#if DEBUG + Console.WriteLine( "installed" ); + foreach ( SingerConfig sc in s_installed_singers1 ) { + Console.WriteLine( "VOICENAME=" + sc.VOICENAME + "; VOICEIDSTR=" + sc.VOICEIDSTR + "; Program=" + sc.Program + "; Original=" + sc.Original ); + } + Console.WriteLine( "singer configs" ); + foreach ( SingerConfig sc in s_singer_configs1 ) { + Console.WriteLine( "VOICENAME=" + sc.VOICENAME + "; VOICEIDSTR=" + sc.VOICEIDSTR + "; Program=" + sc.Program + "; Original=" + sc.Original ); + } +#endif + } + + /// + /// VOCALOID2システムのプロパティを取得 + /// + private static void init_vocalo2() { + // 最初はvstiとeditorのパスを取得 + RegistryKey v2application = Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID2\\APPLICATION", false ); + if ( v2application == null ) { + v2application = Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID2_DEMO\\APPLICATION", false ); + } + if ( v2application != null ) { + string[] keys = v2application.GetSubKeyNames(); + for ( int i = 0; i < keys.Length; i++ ) { + RegistryKey key = v2application.OpenSubKey( keys[i], false ); + if ( key != null ) { + string name = (string)key.GetValue( "PATH" ); + if ( name.ToLower().EndsWith( "\\vocaloid2.dll" ) ) { + s_dll_path2 = name; + } else if ( name.ToLower().EndsWith( "\\vocaloid2_demo.dll" ) ) { + s_dll_path2 = name; + } else if ( name.ToLower().EndsWith( "\\vocaloid2.exe" ) ) { + s_editor_path2 = name; + } + key.Close(); + } + } + v2application.Close(); + } + + // 歌声データベースを取得 + RegistryKey v2database = Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID2\\DATABASE\\VOICE", false ); + if ( v2database != null ) { + // データベース(というよりもvoice.map)が保存されているパスを取得 + s_voicedbdir2 = (string)v2database.GetValue( "VOICEDIR", "" ); + // インストールされている歌手のVOICEIDSTRを列挙 + string[] singer_voiceidstrs = v2database.GetSubKeyNames(); + List vvoice_keys = new List(); + List vvoice_values = new List(); + foreach ( string voiceidstr in singer_voiceidstrs ) { + RegistryKey singer = v2database.OpenSubKey( voiceidstr ); + if ( singer == null ) { + continue; + } + string installdir = (string)singer.GetValue( "INSTALLDIR", "" ); +#if DEBUG + Console.WriteLine( "installdir=" + installdir ); +#endif + RegistryKey vvoice = singer.OpenSubKey( "vvoice" ); + if ( vvoice != null ) { + string[] vvoices = vvoice.GetValueNames(); + + // インストールされた歌手の.vvdを読みにいく + // installdir以下の、拡張子.vvdのファイルを探す + foreach ( string file in Directory.GetFiles( Path.Combine( installdir, voiceidstr ), "*.vvd" ) ) { + SingerConfig config = SingerConfig.fromVvd( file, 0 ); //とりあえずプログラムチェンジは0 + s_installed_singers2.Add( config ); + } + + // vvoice*.vvdを読みにいく。場所は、installdirではなく、s_voicedbdir2 + foreach ( string s in vvoices ) { + string file = Path.Combine( s_voicedbdir2, s + ".vvd" ); + if ( File.Exists( file ) ) { + SingerConfig config = SingerConfig.fromVvd( file, 0 ); + vvoice_keys.Add( s ); + vvoice_values.Add( config ); + } + } + } + singer.Close(); + } + + // voice.mapを読み込んで、s_singer_configs2のプログラムチェンジを更新する + string map = Path.Combine( s_voicedbdir2, "voice.map" ); + if ( File.Exists( map ) ) { + using ( FileStream fs = new FileStream( map, FileMode.Open, FileAccess.Read ) ) { + byte[] dat = new byte[8]; + fs.Seek( 0x20, SeekOrigin.Begin ); + for ( int i = 0; i < MAX_SINGERS; i++ ) { + fs.Read( dat, 0, 8 ); + ulong value = makelong_le( dat ); + if ( value >= 1 ) { +#if DEBUG + Console.WriteLine( "value=" + value ); +#endif + for ( int j = 0; j < vvoice_keys.Count; j++ ) { + if ( vvoice_keys[j] == "vvoice" + value ) { + vvoice_values[j].Program = i; + } + } + } + } + } + } + + // s_installed_singers2のSingerConfigのProgramとOriginalを適当に頒番する + for ( int i = 0; i < s_installed_singers2.Count; i++ ) { + s_installed_singers2[i].Program = i; + s_installed_singers2[i].Original = i; + } + + // s_singer_configs2を更新 + for ( int i = 0; i < vvoice_values.Count; i++ ) { + for ( int j = 0; j < s_installed_singers2.Count; j++ ) { + if ( vvoice_values[i].VOICEIDSTR == s_installed_singers2[j].VOICEIDSTR ) { + vvoice_values[i].Original = s_installed_singers2[j].Program; + break; + } + } + s_singer_configs2.Add( vvoice_values[i] ); + } + v2database.Close(); + } +#if DEBUG + Console.WriteLine( "installed" ); + foreach ( SingerConfig sc in s_installed_singers2 ) { + Console.WriteLine( "VOICENAME=" + sc.VOICENAME + "; VOICEIDSTR=" + sc.VOICEIDSTR + "; Program=" + sc.Program + "; Original=" + sc.Original ); + } + Console.WriteLine( "singer configs" ); + foreach ( SingerConfig sc in s_singer_configs2 ) { + Console.WriteLine( "VOICENAME=" + sc.VOICENAME + "; VOICEIDSTR=" + sc.VOICEIDSTR + "; Program=" + sc.Program + "; Original=" + sc.Original ); + } +#endif + } + + /// + /// Transform the byte array(length=8) to unsigned long, assuming that the byte array is little endian. + /// + /// + /// + public static ulong makelong_le( byte[] oct ) { + return (ulong)oct[7] << 56 | (ulong)oct[6] << 48 | (ulong)oct[5] << 40 | (ulong)oct[4] << 32 | (ulong)oct[3] << 24 | (ulong)oct[2] << 16 | (ulong)oct[1] << 8 | (ulong)oct[0]; + } + } + +} diff --git a/trunk/Boare.Lib.Vsq/VsqBPList.cs b/trunk/Boare.Lib.Vsq/VsqBPList.cs index 8c45c59..b0f1df8 100644 --- a/trunk/Boare.Lib.Vsq/VsqBPList.cs +++ b/trunk/Boare.Lib.Vsq/VsqBPList.cs @@ -23,16 +23,20 @@ namespace Boare.Lib.Vsq { /// [Serializable] public class VsqBPList : ICloneable { - private SortedList m_list = new SortedList(); + private SortedList m_list = new SortedList(); public int Default = 0; public int Maximum = 127; public int Minimum = 0; + /// + /// このリストに設定されたidの最大値.次にデータ点が追加されたときは,個の値+1がidとして利用される.削除された場合でも減らない + /// + private int m_max_id = 0; private class KeyClockIterator : Iterator { - private SortedList m_list; + private SortedList m_list; private int m_pos; - public KeyClockIterator( SortedList list ) { + public KeyClockIterator( SortedList list ) { m_list = list; m_pos = -1; } @@ -71,12 +75,13 @@ namespace Boare.Lib.Vsq { int count = -1; foreach ( int key in m_list.Keys ) { count++; - ret += (count == 0 ? "" : "," ) + key + "=" + m_list[key]; + ret += (count == 0 ? "" : "," ) + key + "=" + m_list[key].value; } return ret; } set { m_list.Clear(); + m_max_id = 0; string[] spl = value.Split( ',' ); for ( int i = 0; i < spl.Length; i++ ) { string[] spl2 = spl[i].Split( '=' ); @@ -84,7 +89,8 @@ namespace Boare.Lib.Vsq { continue; } try { - m_list.Add( int.Parse( spl2[0] ), int.Parse( spl2[1] ) ); + m_list.Add( int.Parse( spl2[0] ), new VsqBPPair( int.Parse( spl2[1] ), m_max_id + 1 ) ); + m_max_id++; } catch ( Exception ex ) { #if DEBUG Console.WriteLine( " ex=" + ex ); @@ -115,6 +121,7 @@ namespace Boare.Lib.Vsq { Default = default_value; Maximum = maximum; Minimum = minimum; + m_max_id = 0; } /// @@ -169,21 +176,47 @@ namespace Boare.Lib.Vsq { public void add( int clock, int value ) { lock ( m_list ) { if ( m_list.ContainsKey( clock ) ) { - m_list[clock] = value; + VsqBPPair v = m_list[clock]; + v.value = value; + m_list[clock] = v; } else { - m_list.Add( clock, value ); + VsqBPPair v = new VsqBPPair( value, m_max_id + 1 ); + m_max_id++; + m_list.Add( clock, v ); } } } public int getElement( int index ) { - return m_list[m_list.Keys[index]]; + return m_list[m_list.Keys[index]].value; } public int getKeyClock( int index ) { return m_list.Keys[index]; } + public int findValueFromID( int id ) { + int c = m_list.Keys.Count; + foreach ( int key in m_list.Keys ) { + if ( m_list[key].id == id ) { + return m_list[key].value; + } + } + return Default; + } + + public void setValueForID( int id, int value ) { + int c = m_list.Keys.Count; + foreach ( int key in m_list.Keys ) { + if ( m_list[key].id == id ) { + VsqBPPair v = m_list[key]; + v.value = value; + m_list[key] = v; + break; + } + } + } + public int getValue( int clock, ref int index ) { if ( m_list.Count == 0 ) { return Default; @@ -196,7 +229,7 @@ namespace Boare.Lib.Vsq { if ( clock < keyclock ) { if ( i > 0 ) { index = i; - return m_list[m_list.Keys[i - 1]]; + return m_list[m_list.Keys[i - 1]].value; } else { index = i; return Default; @@ -204,7 +237,7 @@ namespace Boare.Lib.Vsq { } } index = m_list.Keys.Count - 1; - return m_list[m_list.Keys[m_list.Keys.Count - 1]]; + return m_list[m_list.Keys[m_list.Keys.Count - 1]].value; } } @@ -216,38 +249,13 @@ namespace Boare.Lib.Vsq { int keyclock = m_list.Keys[i]; if ( clock < keyclock ) { if ( i > 0 ) { - return m_list[m_list.Keys[i - 1]]; + return m_list[m_list.Keys[i - 1]].value; } else { return Default; } } } - return m_list[m_list.Keys[m_list.Keys.Count - 1]]; - } - } - - public int OLD_getElement( int clock ) { - if ( m_list.Count == 0 ) { - return Default; - } else { - if ( m_list.ContainsKey( clock ) ) { - return m_list[clock]; - } else { - int index = 0; - int prev = 0; - foreach ( int key in m_list.Keys ) { - if ( clock < key ) { - index = prev; - break; - } - prev = key; - } - if ( m_list.ContainsKey( index ) ) { - return m_list[index]; - } else { - return Default; - } - } + return m_list[m_list.Keys[m_list.Keys.Count - 1]].value; } } @@ -265,7 +273,7 @@ namespace Boare.Lib.Vsq { public void print( StreamWriter writer ) { bool first = true; foreach ( int key in m_list.Keys ) { - int val = m_list[key]; + int val = m_list[key].value; if ( first ) { writer.WriteLine( key + "=" + val ); first = false; @@ -287,7 +295,7 @@ namespace Boare.Lib.Vsq { writer.writeLine( header ); first = false; } - int val = m_list[key]; + int val = m_list[key].value; writer.writeLine( key + "=" + val ); } } @@ -304,7 +312,9 @@ namespace Boare.Lib.Vsq { string[] spl = last_line.Split( new char[] { '=' } ); int i1 = int.Parse( spl[0] ); int i2 = int.Parse( spl[1] ); - m_list.Add( i1, i2 ); + VsqBPPair v = new VsqBPPair( i2, m_max_id + 1 ); + m_max_id++; + m_list.Add( i1, v ); if ( reader.peek() < 0 ) { break; } else { diff --git a/trunk/Boare.Lib.Vsq/VsqBPPair.cs b/trunk/Boare.Lib.Vsq/VsqBPPair.cs new file mode 100644 index 0000000..09bb261 --- /dev/null +++ b/trunk/Boare.Lib.Vsq/VsqBPPair.cs @@ -0,0 +1,15 @@ +using System; + +namespace Boare.Lib.Vsq { + + public struct VsqBPPair { + public int value; + public int id; + + public VsqBPPair( int value_, int id_ ) { + value = value_; + id = id_; + } + } + +} diff --git a/trunk/Boare.Lib.Vsq/VsqEventList.cs b/trunk/Boare.Lib.Vsq/VsqEventList.cs index 69d4eb9..731dcc9 100644 --- a/trunk/Boare.Lib.Vsq/VsqEventList.cs +++ b/trunk/Boare.Lib.Vsq/VsqEventList.cs @@ -32,12 +32,29 @@ namespace Boare.Lib.Vsq { m_ids = new List(); } + public VsqEvent findFromID( int internal_id ) { + foreach ( VsqEvent item in Events ) { + if ( item.InternalID == internal_id ) { + return item; + } + } + return null; + } + + public void setForID( int internal_id, VsqEvent value ) { + int c = Events.Count; + for ( int i = 0; i < c; i++ ) { + if ( Events[i].InternalID == internal_id ) { + Events[i] = value; + break; + } + } + } + public void sort() { lock ( this ) { Events.Sort(); - for ( int i = 0; i < Events.Count; i++ ) { - m_ids[i] = Events[i].InternalID; - } + updateIDList(); } } @@ -105,6 +122,10 @@ namespace Boare.Lib.Vsq { for ( int i = 0; i < Events.Count; i++ ) { m_ids.Add( Events[i].InternalID ); } + } else { + for ( int i = 0; i < Events.Count; i++ ) { + m_ids[i] = Events[i].InternalID; + } } } } diff --git a/trunk/Boare.Lib.Vsq/VsqFile.cs b/trunk/Boare.Lib.Vsq/VsqFile.cs index c98daf8..8b0bb07 100644 --- a/trunk/Boare.Lib.Vsq/VsqFile.cs +++ b/trunk/Boare.Lib.Vsq/VsqFile.cs @@ -57,7 +57,8 @@ namespace Boare.Lib.Vsq { /// public void speedingUp( double order ) { lock ( TempoTable ) { - for ( int i = 0; i < TempoTable.Count; i++ ) { + int c = TempoTable.Count; + for ( int i = 0; i < c; i++ ) { TempoTable[i].Tempo = (int)(TempoTable[i].Tempo / order); } } @@ -116,7 +117,8 @@ namespace Boare.Lib.Vsq { int new_clock = (int)command.Args[2]; int index = -1; - for ( int i = 0; i < TempoTable.Count; i++ ) { + int c = TempoTable.Count; + for ( int i = 0; i < c; i++ ) { if ( TempoTable[i].Clock == clock ) { index = i; break; @@ -141,7 +143,8 @@ namespace Boare.Lib.Vsq { // 編集領域を更新 int affected_clock = Math.Min( clock, new_clock ); - for ( int i = 1; i < Track.Count; i++ ) { + c = Track.Count; + for ( int i = 1; i < c; i++ ) { if ( affected_clock < Track[i].getEditedStart() ) { Track[i].setEditedStart( affected_clock ); } @@ -160,7 +163,8 @@ namespace Boare.Lib.Vsq { int index = -1; affected_clock = Math.Min( affected_clock, clocks[i] ); affected_clock = Math.Min( affected_clock, new_clocks[i] ); - for ( int j = 0; j < TempoTable.Count; j++ ) { + int tempo_table_count = TempoTable.Count; + for ( int j = 0; j < tempo_table_count; j++ ) { if ( TempoTable[j].Clock == clocks[i] ) { index = j; break; @@ -181,7 +185,8 @@ namespace Boare.Lib.Vsq { } updateTempoInfo(); updateTotalClocks(); - for ( int i = 1; i < Track.Count; i++ ) { + int track_count = Track.Count; + for ( int i = 1; i < track_count; i++ ) { if ( affected_clock < Track[i].getEditedStart() ) { Track[i].setEditedStart( affected_clock ); } @@ -196,7 +201,8 @@ namespace Boare.Lib.Vsq { int denominator = (int)command.Args[2]; int new_barcount = (int)command.Args[3]; int index = -1; - for ( int i = 0; i < TimesigTable.Count; i++ ) { + int timesig_table_count = TimesigTable.Count; + for ( int i = 0; i < timesig_table_count; i++ ) { if ( barcount == TimesigTable[i].BarCount ) { index = i; break; @@ -232,7 +238,8 @@ namespace Boare.Lib.Vsq { for ( int i = 0; i < barcounts.Length; i++ ) { int index = -1; // すでに拍子が登録されているかどうかを検査 - for ( int j = 0; j < TimesigTable.Count; j++ ) { + int timesig_table_count = TimesigTable.Count; + for ( int j = 0; j < timesig_table_count; j++ ) { if ( TimesigTable[j].BarCount == barcounts[i] ) { index = j; break; @@ -265,19 +272,22 @@ namespace Boare.Lib.Vsq { VsqFile vsq = (VsqFile)command.Args[0]; VsqFile inv = (VsqFile)this.Clone(); Track.Clear(); - for ( int i = 0; i < vsq.Track.Count; i++ ) { + int track_count = vsq.Track.Count; + for ( int i = 0; i < track_count; i++ ) { Track.Add( (VsqTrack)vsq.Track[i].Clone() ); } #if USE_TEMPO_LIST m_tempo_table = (TempoTable)vsq.m_tempo_table.Clone(); #else TempoTable.Clear(); - for ( int i = 0; i < vsq.TempoTable.Count; i++ ) { + int tempo_table_count = vsq.TempoTable.Count; + for ( int i = 0; i < tempo_table_count; i++ ) { TempoTable.Add( (TempoTableEntry)vsq.TempoTable[i].Clone() ); } #endif TimesigTable.Clear(); - for ( int i = 0; i < vsq.TimesigTable.Count; i++ ) { + int timesig_table_count = vsq.TimesigTable.Count; + for ( int i = 0; i < timesig_table_count; i++ ) { TimesigTable.Add( (TimeSigTableEntry)vsq.TimesigTable[i].Clone() ); } m_tpq = vsq.m_tpq; @@ -285,7 +295,6 @@ namespace Boare.Lib.Vsq { m_base_tempo = vsq.m_base_tempo; Master = (VsqMaster)vsq.Master.Clone(); Mixer = (VsqMixer)vsq.Mixer.Clone(); - //m_premeasure_clocks = vsq.m_premeasure_clocks; updateTotalClocks(); return VsqCommand.generateCommandReplace( inv ); #endregion @@ -293,11 +302,8 @@ namespace Boare.Lib.Vsq { #region EventAdd int track = (int)command.Args[0]; VsqEvent item = (VsqEvent)command.Args[1]; - //int key = this.Tracks[track].GetNextId( 0 ); - //item.InternalID = key; Track[track].addEvent( item ); VsqCommand ret = VsqCommand.generateCommandEventDelete( track, item.InternalID ); - //this.Tracks[track].Events.Sort(); updateTotalClocks(); if ( item.Clock < Track[track].getEditedStart() ) { Track[track].setEditedStart( item.Clock ); @@ -305,6 +311,7 @@ namespace Boare.Lib.Vsq { if ( Track[track].getEditedEnd() < item.Clock + item.ID.Length ) { Track[track].setEditedEnd( item.Clock + item.ID.Length ); } + Track[track].sortEvent(); return ret; #endregion } else if ( type == VsqCommandType.EventAddRange ) { @@ -321,8 +328,6 @@ namespace Boare.Lib.Vsq { VsqEvent item = (VsqEvent)items[i].Clone(); min_clock = Math.Min( min_clock, item.Clock ); max_clock = Math.Max( max_clock, item.Clock + item.ID.Length ); - //int key = Tracks[track].GetNextId( i ); - //item.InternalID = key; #if DEBUG Console.Write( " i=" + i + "; item.InternalID=" + item.InternalID ); #endif @@ -332,7 +337,6 @@ namespace Boare.Lib.Vsq { Console.WriteLine( " => " + item.InternalID ); #endif } - //Tracks[track].Events.Sort(); updateTotalClocks(); if ( min_clock < Track[track].getEditedStart() ) { Track[track].setEditedStart( min_clock ); @@ -340,6 +344,7 @@ namespace Boare.Lib.Vsq { if ( Track[track].getEditedEnd() < max_clock ) { Track[track].setEditedEnd( max_clock ); } + Track[track].sortEvent(); return VsqCommand.generateCommandEventDeleteRange( track, inv_ids.ToArray() ); #endregion } else if ( type == VsqCommandType.EventDelete ) { @@ -347,23 +352,25 @@ namespace Boare.Lib.Vsq { int internal_id = (int)command.Args[0]; int track = (int)command.Args[1]; VsqEvent[] original = new VsqEvent[1]; - for ( Iterator itr = Track[track].getEventIterator(); itr.hasNext(); ) { + VsqTrack target = Track[track]; + for ( Iterator itr = target.getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_id ) { original[0] = (VsqEvent)item.Clone(); break; } } - if ( original[0].Clock < Track[track].getEditedStart() ) { - Track[track].setEditedStart( original[0].Clock ); + if ( original[0].Clock < target.getEditedStart() ) { + target.setEditedStart( original[0].Clock ); } - if ( Track[track].getEditedEnd() < original[0].Clock + original[0].ID.Length ) { - Track[track].setEditedEnd( original[0].Clock + original[0].ID.Length ); + if ( target.getEditedEnd() < original[0].Clock + original[0].ID.Length ) { + target.setEditedEnd( original[0].Clock + original[0].ID.Length ); } VsqCommand ret = VsqCommand.generateCommandEventAddRange( track, original ); - for ( int i = 0; i < this.Track[track].getEventCount(); i++ ) { - if ( this.Track[track].getEvent( i ).InternalID == internal_id ) { - Track[track].removeEvent( i ); + int count = target.getEventCount(); + for ( int i = 0; i < count; i++ ) { + if ( target.getEvent( i ).InternalID == internal_id ) { + target.removeEvent( i ); break; } } @@ -377,20 +384,22 @@ namespace Boare.Lib.Vsq { List inv = new List(); int min_clock = int.MaxValue; int max_clock = int.MinValue; + VsqTrack target = this.Track[track]; for ( int j = 0; j < internal_ids.Length; j++ ) { - for ( int i = 0; i < Track[track].getEventCount(); i++ ) { - if ( internal_ids[j] == Track[track].getEvent( i ).InternalID ) { - inv.Add( (VsqEvent)Track[track].getEvent( i ).Clone() ); - min_clock = Math.Min( min_clock, Track[track].getEvent( i ).Clock ); - max_clock = Math.Max( max_clock, Track[track].getEvent( i ).Clock + Track[track].getEvent( i ).ID.Length ); - Track[track].removeEvent( i ); + for ( int i = 0; i < target.getEventCount(); i++ ) { + VsqEvent item = target.getEvent( i ); + if ( internal_ids[j] == item.InternalID ) { + inv.Add( (VsqEvent)item.Clone() ); + min_clock = Math.Min( min_clock, item.Clock ); + max_clock = Math.Max( max_clock, item.Clock + item.ID.Length ); + target.removeEvent( i ); break; } } } updateTotalClocks(); - Track[track].setEditedStart( min_clock ); - Track[track].setEditedEnd( max_clock ); + target.setEditedStart( min_clock ); + target.setEditedEnd( max_clock ); return VsqCommand.generateCommandEventAddRange( track, inv.ToArray() ); #endregion } else if ( type == VsqCommandType.EventChangeClock ) { @@ -398,16 +407,16 @@ namespace Boare.Lib.Vsq { int track = (int)command.Args[0]; int internal_id = (int)command.Args[1]; int value = (int)command.Args[2]; - for ( Iterator itr = Track[track].getEventIterator(); itr.hasNext(); ) { + VsqTrack target = this.Track[track]; + for ( Iterator itr = target.getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_id ) { VsqCommand ret = VsqCommand.generateCommandEventChangeClock( track, internal_id, item.Clock ); int min = Math.Min( item.Clock, value ); int max = Math.Max( item.Clock + item.ID.Length, value + item.ID.Length ); - Track[track].setEditedStart( min ); - Track[track].setEditedEnd( max ); + target.setEditedStart( min ); + target.setEditedEnd( max ); item.Clock = value; - //this.Tracks[track].Events.Sort(); updateTotalClocks(); return ret; } @@ -421,7 +430,8 @@ namespace Boare.Lib.Vsq { string phrase = (string)command.Args[2]; string phonetic_symbol = (string)command.Args[3]; bool protect_symbol = (bool)command.Args[4]; - for ( Iterator itr = Track[track].getEventIterator(); itr.hasNext(); ) { + VsqTrack target = this.Track[track]; + for ( Iterator itr = target.getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_id ) { if ( item.ID.type == VsqIDType.Anote ) { @@ -429,8 +439,8 @@ namespace Boare.Lib.Vsq { item.ID.LyricHandle.L0.Phrase = phrase; item.ID.LyricHandle.L0.setPhoneticSymbol( phonetic_symbol ); item.ID.LyricHandle.L0.PhoneticSymbolProtected = protect_symbol; - Track[track].setEditedStart( item.Clock ); - Track[track].setEditedEnd( item.Clock + item.ID.Length ); + target.setEditedStart( item.Clock ); + target.setEditedEnd( item.Clock + item.ID.Length ); updateTotalClocks(); return ret; } @@ -443,14 +453,15 @@ namespace Boare.Lib.Vsq { int track = (int)command.Args[0]; int internal_id = (int)command.Args[1]; int note = (int)command.Args[2]; - for ( Iterator itr = Track[track].getEventIterator(); itr.hasNext(); ) { + VsqTrack target = this.Track[track]; + for ( Iterator itr = target.getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_id ) { VsqCommand ret = VsqCommand.generateCommandEventChangeNote( track, internal_id, item.ID.Note ); item.ID.Note = note; updateTotalClocks(); - Track[track].setEditedStart( item.Clock ); - Track[track].setEditedEnd( item.Clock + item.ID.Length ); + target.setEditedStart( item.Clock ); + target.setEditedEnd( item.Clock + item.ID.Length ); return ret; } } @@ -462,17 +473,17 @@ namespace Boare.Lib.Vsq { int internal_id = (int)command.Args[1]; int clock = (int)command.Args[2]; int note = (int)command.Args[3]; - for ( Iterator itr = Track[track].getEventIterator(); itr.hasNext(); ) { + VsqTrack target = this.Track[track]; + for ( Iterator itr = target.getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_id ) { VsqCommand ret = VsqCommand.generateCommandEventChangeClockAndNote( track, internal_id, item.Clock, item.ID.Note ); int min = Math.Min( item.Clock, clock ); int max = Math.Max( item.Clock + item.ID.Length, clock + item.ID.Length ); - Track[track].setEditedStart( min ); - Track[track].setEditedEnd( max ); + target.setEditedStart( min ); + target.setEditedEnd( max ); item.Clock = clock; item.ID.Note = note; - //this.Tracks[track].Events.Sort(); updateTotalClocks(); return ret; } @@ -484,7 +495,6 @@ namespace Boare.Lib.Vsq { int track = (int)command.Args[0]; string curve = (string)command.Args[1]; List com = (List)command.Args[2]; - VsqCommand inv = null; List edit = new List(); if ( com != null ) { @@ -772,6 +782,7 @@ namespace Boare.Lib.Vsq { Track[track].setEditedEnd( max ); item.ID.Length = new_length; item.Clock = new_clock; + Track[track].sortEvent(); updateTotalClocks(); return ret; } @@ -880,6 +891,7 @@ namespace Boare.Lib.Vsq { item.Clock = new_clock; Track[track].setEditedStart( min ); Track[track].setEditedEnd( max ); + Track[track].sortEvent(); updateTotalClocks(); return ret; } @@ -911,6 +923,7 @@ namespace Boare.Lib.Vsq { } } } + Track[track].sortEvent(); updateTotalClocks(); return VsqCommand.generateCommandEventChangeClockAndIDContaintsRange( track, @@ -963,6 +976,8 @@ namespace Boare.Lib.Vsq { break; } } + Track[track].sortEvent(); + updateTotalClocks(); return ret; #endregion } else if ( type == VsqCommandType.EventReplaceRange ) { @@ -982,6 +997,8 @@ namespace Boare.Lib.Vsq { } } } + Track[track].sortEvent(); + updateTotalClocks(); ret = VsqCommand.generateCommandEventReplaceRange( track, reverse ); return ret; #endregion @@ -1002,6 +1019,7 @@ namespace Boare.Lib.Vsq { // テンポ情報の削除、シフト bool changed = true; List buf = new List( TempoTable ); + int tempo_at_clock_start = getTempoAt( clock_start ); int tempo_at_clock_end = getTempoAt( clock_end ); TempoTable.Clear(); bool just_on_clock_end_added = false; @@ -1015,15 +1033,17 @@ namespace Boare.Lib.Vsq { TempoTable.Add( tte ); just_on_clock_end_added = true; } else { - if ( !just_on_clock_end_added ) { - TempoTable.Add( new TempoTableEntry( clock_start, tempo_at_clock_end, 0.0 ) ); - just_on_clock_end_added = true; + if ( tempo_at_clock_start != tempo_at_clock_end ) { + if ( !just_on_clock_end_added ) { + TempoTable.Add( new TempoTableEntry( clock_start, tempo_at_clock_end, 0.0 ) ); + just_on_clock_end_added = true; + } } TempoTable.Add( tte ); } } } - if ( !just_on_clock_end_added ) { + if ( tempo_at_clock_start != tempo_at_clock_end && !just_on_clock_end_added ) { TempoTable.Add( new TempoTableEntry( clock_start, tempo_at_clock_end, 0.0 ) ); } updateTempoInfo(); @@ -1312,11 +1332,13 @@ namespace Boare.Lib.Vsq { /// /// public double getSecFromClock( double clock ) { - for ( int i = TempoTable.Count - 1; i >= 0; i-- ) { - if ( TempoTable[i].Clock < clock ) { - double init = TempoTable[i].Time; - double dclock = clock - TempoTable[i].Clock; - double sec_per_clock1 = TempoTable[i].Tempo * 1e-6 / 480.0; + int c = TempoTable.Count; + for ( int i = c - 1; i >= 0; i-- ) { + TempoTableEntry item = TempoTable[i]; + if ( item.Clock < clock ) { + double init = item.Time; + double dclock = clock - item.Clock; + double sec_per_clock1 = item.Tempo * 1e-6 / 480.0; return init + dclock * sec_per_clock1; } } @@ -1338,18 +1360,20 @@ namespace Boare.Lib.Vsq { int tempo = m_base_tempo; double base_clock = 0; double base_time = 0f; - if ( TempoTable.Count == 0 ) { + int c = TempoTable.Count; + if ( c == 0 ) { tempo = m_base_tempo; base_clock = 0; base_time = 0f; - } else if ( TempoTable.Count == 1 ) { + } else if ( c == 1 ) { tempo = TempoTable[0].Tempo; base_clock = TempoTable[0].Clock; base_time = TempoTable[0].Time; } else { - for ( int i = TempoTable.Count - 1; i >= 0; i-- ) { - if ( TempoTable[i].Time < time ) { - return TempoTable[i].Clock + (time - TempoTable[i].Time) * m_tpq * 1000000.0 / TempoTable[i].Tempo; + for ( int i = c - 1; i >= 0; i-- ) { + TempoTableEntry item = TempoTable[i]; + if ( item.Time < time ) { + return item.Clock + (time - item.Time) * m_tpq * 1000000.0 / item.Tempo; } } } @@ -1366,7 +1390,8 @@ namespace Boare.Lib.Vsq { /// public void getTimesigAt( int clock, out int numerator, out int denominator ) { int index = 0; - for ( int i = TimesigTable.Count - 1; i >= 0; i-- ) { + int c = TimesigTable.Count; + for ( int i = c - 1; i >= 0; i-- ) { index = i; if ( TimesigTable[i].Clock <= clock ) { break; @@ -1378,17 +1403,19 @@ namespace Boare.Lib.Vsq { public void getTimesigAt( int clock, out int numerator, out int denominator, out int bar_count ) { int index = 0; - for ( int i = TimesigTable.Count - 1; i >= 0; i-- ) { + int c = TimesigTable.Count; + for ( int i = c - 1; i >= 0; i-- ) { index = i; if ( TimesigTable[i].Clock <= clock ) { break; } } - numerator = TimesigTable[index].Numerator; - denominator = TimesigTable[index].Denominator; - int diff = clock - TimesigTable[index].Clock; + TimeSigTableEntry item = TimesigTable[index]; + numerator = item.Numerator; + denominator = item.Denominator; + int diff = clock - item.Clock; int clock_per_bar = 480 * 4 / denominator * numerator; - bar_count = TimesigTable[index].BarCount + diff / clock_per_bar; + bar_count = item.BarCount + diff / clock_per_bar; } /// @@ -1398,7 +1425,8 @@ namespace Boare.Lib.Vsq { /// public int getTempoAt( int clock ) { int index = 0; - for ( int i = TempoTable.Count - 1; i >= 0; i-- ) { + int c = TempoTable.Count; + for ( int i = c - 1; i >= 0; i-- ) { index = i; if ( TempoTable[i].Clock <= clock ) { break; @@ -1414,16 +1442,18 @@ namespace Boare.Lib.Vsq { /// public int getClockFromBarCount( int bar_count ) { int index = 0; - for ( int i = TimesigTable.Count - 1; i >= 0; i-- ) { + int c = TimesigTable.Count; + for ( int i = c - 1; i >= 0; i-- ) { index = i; if ( TimesigTable[i].BarCount <= bar_count ) { break; } } - int numerator = TimesigTable[index].Numerator; - int denominator = TimesigTable[index].Denominator; - int init_clock = TimesigTable[index].Clock; - int init_bar_count = TimesigTable[index].BarCount; + TimeSigTableEntry item = TimesigTable[index]; + int numerator = item.Numerator; + int denominator = item.Denominator; + int init_clock = item.Clock; + int init_bar_count = item.BarCount; int clock_per_bar = numerator * 480 * 4 / denominator; return init_clock + (bar_count - init_bar_count) * clock_per_bar; } @@ -1435,7 +1465,8 @@ namespace Boare.Lib.Vsq { /// public int getBarCountFromClock( int clock ) { int index = 0; - for ( int i = TimesigTable.Count - 1; i >= 0; i-- ) { + int c = TimesigTable.Count; + for ( int i = c - 1; i >= 0; i-- ) { index = i; if ( TimesigTable[i].Clock <= clock ) { break; @@ -1569,15 +1600,15 @@ namespace Boare.Lib.Vsq { prev_time = 0.0; int count = -1; for ( int j = 0; j < midi_event.Count; j++ ) { - if ( midi_event[j].FirstByte == 0xff && midi_event[j].Data.Length >= 4 && midi_event[j].Data[0] == 0x51 ) { + if ( midi_event[j].firstByte == 0xff && midi_event[j].data.Length >= 4 && midi_event[j].data[0] == 0x51 ) { count++; - if ( count == 0 && midi_event[j].Clock != 0 ) { + if ( count == 0 && midi_event[j].clock != 0 ) { TempoTable.Add( new TempoTableEntry( 0, 500000, 0.0 ) ); m_base_tempo = 500000; prev_tempo = 500000; } - int current_tempo = midi_event[j].Data[1] << 16 | midi_event[j].Data[2] << 8 | midi_event[j].Data[3]; - int current_index = (int)midi_event[j].Clock; + int current_tempo = midi_event[j].data[1] << 16 | midi_event[j].data[2] << 8 | midi_event[j].data[3]; + int current_index = (int)midi_event[j].clock; thistime = prev_time + (double)(prev_tempo) * (double)(current_index - prev_index) / (m_tpq * 1000000.0); TempoTable.Add( new TempoTableEntry( current_index, current_tempo, thistime ) ); prev_tempo = current_tempo; @@ -1598,11 +1629,11 @@ namespace Boare.Lib.Vsq { //m_timesig_table.Add( new TimeSigTableEntry( 0, numer, dnomi, 0 ) ); count = -1; for ( int j = 0; j < midi_event.Count; j++ ) { - if ( midi_event[j].FirstByte == 0xff && midi_event[j].Data.Length >= 5 && midi_event[j].Data[0] == 0x58 ) { + if ( midi_event[j].firstByte == 0xff && midi_event[j].data.Length >= 5 && midi_event[j].data[0] == 0x58 ) { count++; - numer = midi_event[j].Data[1]; + numer = midi_event[j].data[1]; dnomi = 1; - for ( int i = 0; i < midi_event[j].Data[2]; i++ ) { + for ( int i = 0; i < midi_event[j].data[2]; i++ ) { dnomi = dnomi * 2; } if ( count == 0 ){ @@ -1610,11 +1641,11 @@ namespace Boare.Lib.Vsq { int denominator = 4; int clock = 0; int bar_count = 0; - if ( midi_event[j].Clock == 0 ) { + if ( midi_event[j].clock == 0 ) { TimesigTable.Add( new TimeSigTableEntry( 0, numer, dnomi, 0 ) ); } else { TimesigTable.Add( new TimeSigTableEntry( 0, 4, 4, 0 ) ); - TimesigTable.Add( new TimeSigTableEntry( 0, numer, dnomi, (int)midi_event[j].Clock / (480 * 4) ) ); + TimesigTable.Add( new TimeSigTableEntry( 0, numer, dnomi, (int)midi_event[j].clock / (480 * 4) ) ); count++; } } else { @@ -1623,8 +1654,8 @@ namespace Boare.Lib.Vsq { int clock = TimesigTable[count - 1].Clock; int bar_count = TimesigTable[count - 1].BarCount; int dif = 480 * 4 / denominator * numerator;//1小節が何クロックか? - bar_count += ((int)midi_event[j].Clock - clock) / dif; - TimesigTable.Add( new TimeSigTableEntry( (int)midi_event[j].Clock, numer, dnomi, bar_count ) ); + bar_count += ((int)midi_event[j].clock - clock) / dif; + TimesigTable.Add( new TimeSigTableEntry( (int)midi_event[j].clock, numer, dnomi, bar_count ) ); } } } @@ -1774,7 +1805,7 @@ namespace Boare.Lib.Vsq { public List generateMetaTextEvent( int track ) { string _NL = "" + (char)0x0a; List ret = new List(); - using ( TextMemoryStream sr = new TextMemoryStream( FileAccess.ReadWrite ) ) { + using ( TextMemoryStream sr = new TextMemoryStream() ) { Track[track].printMetaText( sr, TotalClocks + 120, calculatePreMeasureInClock() ); sr.rewind(); int line_count = -1; @@ -1793,12 +1824,12 @@ namespace Boare.Lib.Vsq { tmp = tmp.Substring( 127 ); line_char = work.ToCharArray(); MidiEvent add = new MidiEvent(); - add.Clock = 0; - add.FirstByte = 0xff; //ステータス メタ* - add.Data = new byte[line_char.Length + 1]; - add.Data[0] = 0x01; //メタテキスト + add.clock = 0; + add.firstByte = 0xff; //ステータス メタ* + add.data = new byte[line_char.Length + 1]; + add.data[0] = 0x01; //メタテキスト for ( int i = 0; i < line_char.Length; i++ ) { - add.Data[i + 1] = (byte)line_char[i]; + add.data[i + 1] = (byte)line_char[i]; } ret.Add( add ); } @@ -1811,12 +1842,12 @@ namespace Boare.Lib.Vsq { tmp = tmp.Substring( 127 ); line_char = work.ToCharArray(); MidiEvent add = new MidiEvent(); - add.Clock = 0; - add.FirstByte = 0xff; - add.Data = new byte[line_char.Length + 1]; - add.Data[0] = 0x01; + add.clock = 0; + add.firstByte = 0xff; + add.data = new byte[line_char.Length + 1]; + add.data[0] = 0x01; for ( int i = 0; i < line_char.Length; i++ ) { - add.Data[i + 1] = (byte)line_char[i]; + add.data[i + 1] = (byte)line_char[i]; } ret.Add( add ); line_count++; @@ -1824,11 +1855,11 @@ namespace Boare.Lib.Vsq { } line_char = tmp.ToCharArray(); MidiEvent add0 = new MidiEvent(); - add0.FirstByte = 0xff; - add0.Data = new byte[line_char.Length + 1]; - add0.Data[0] = 0x01; + add0.firstByte = 0xff; + add0.data = new byte[line_char.Length + 1]; + add0.data[0] = 0x01; for ( int i = 0; i < line_char.Length; i++ ) { - add0.Data[i + 1] = (byte)line_char[i]; + add0.data[i + 1] = (byte)line_char[i]; } ret.Add( add0 ); } @@ -1859,20 +1890,14 @@ namespace Boare.Lib.Vsq { List meta = vsq.generateMetaTextEvent( track ); long lastclock = 0; for ( int i = 0; i < meta.Count; i++ ) { - writeFlexibleLengthUnsignedLong( fs, (ulong)(meta[i].Clock - lastclock) ); + writeFlexibleLengthUnsignedLong( fs, (ulong)(meta[i].clock - lastclock) ); meta[i].writeData( fs ); - lastclock = meta[i].Clock; + lastclock = meta[i].clock; } int last = 0; VsqNrpn[] data = generateNRPN( vsq, track, msPreSend ); NrpnData[] nrpns = VsqNrpn.convert( data ); -#if DEBUG - bocoree.debug.push_log( "VsqFile.printTrack; nrpns" ); - for ( int i = 0; i < nrpns.Length; i++ ) { - bocoree.debug.push_log( " clock,parameter,value=" + nrpns[i].getClock() + "," + Convert.ToString( nrpns[i].getParameter(), 16 ) + "," + Convert.ToString( nrpns[i].Value, 16 ) ); - } -#endif for ( int i = 0; i < nrpns.Length; i++ ) { writeFlexibleLengthUnsignedLong( fs, (ulong)(nrpns[i].getClock() - last) ); fs.WriteByte( 0xb0 ); @@ -1987,9 +2012,8 @@ namespace Boare.Lib.Vsq { int i = clock - vsq.getPresendClockAt( clock, msPreSend ); VsqNrpn add = new VsqNrpn( i, (ushort)NRPN.CC_BS_VERSION_AND_DEVICE, 0x00, 0x00 ); - add.append( NRPN.CC_BS_DELAY, delay0, delay1 ); - add.append( NRPN.CC_BS_LANGUAGE_TYPE, (byte)ve.ID.IconHandle.Language ); - //add.append( NRPN.PC_VERSION_AND_DEVICE, 0x00, 0x00 ); + add.append( NRPN.CC_BS_DELAY, delay0, delay1, true ); + add.append( NRPN.CC_BS_LANGUAGE_TYPE, (byte)ve.ID.IconHandle.Language, true ); add.append( NRPN.PC_VOICE_TYPE, (byte)ve.ID.IconHandle.Program ); return new VsqNrpn[] { add }; } @@ -2019,24 +2043,24 @@ namespace Boare.Lib.Vsq { byte delay0, delay1; getMsbAndLsb( (ushort)msPreSend, out delay0, out delay1 ); add = new VsqNrpn( clock - vsq.getPresendClockAt( clock, msPreSend ), NRPN.CVM_NM_VERSION_AND_DEVICE, 0x00, 0x00 ); - add.append( NRPN.CVM_NM_DELAY, delay0, delay1 ); - add.append( NRPN.CVM_NM_NOTE_NUMBER, (byte)ve.ID.Note ); // Note number + add.append( NRPN.CVM_NM_DELAY, delay0, delay1, true ); + add.append( NRPN.CVM_NM_NOTE_NUMBER, (byte)ve.ID.Note, true ); // Note number } else { add = new VsqNrpn( clock - vsq.getPresendClockAt( clock, msPreSend ), NRPN.CVM_NM_NOTE_NUMBER, (byte)ve.ID.Note ); // Note number } - add.append( NRPN.CVM_NM_VELOCITY, (byte)ve.ID.Dynamics ); // Velocity - add.append( NRPN.CVM_NM_NOTE_DURATION, duration0, duration1 ); // Note duration - add.append( NRPN.CVM_NM_NOTE_LOCATION, note_loc ); // Note Location + add.append( NRPN.CVM_NM_VELOCITY, (byte)ve.ID.Dynamics, true ); // Velocity + add.append( NRPN.CVM_NM_NOTE_DURATION, duration0, duration1, true ); // Note duration + add.append( NRPN.CVM_NM_NOTE_LOCATION, note_loc, true ); // Note Location if ( ve.ID.VibratoHandle != null ) { - add.append( NRPN.CVM_NM_INDEX_OF_VIBRATO_DB, 0x00, 0x00 ); + add.append( NRPN.CVM_NM_INDEX_OF_VIBRATO_DB, 0x00, 0x00, true ); int vibrato_type = (int)VibratoTypeUtil.getVibratoTypeFromIconID( ve.ID.VibratoHandle.IconID ); int note_length = ve.ID.Length; int vibrato_delay = ve.ID.VibratoDelay; byte bVibratoDuration = (byte)((float)(note_length - vibrato_delay) / (float)note_length * 127); byte bVibratoDelay = (byte)(0x7f - bVibratoDuration); - add.append( NRPN.CVM_NM_VIBRATO_CONFIG, (byte)vibrato_type, bVibratoDuration ); - add.append( NRPN.CVM_NM_VIBRATO_DELAY, bVibratoDelay ); + add.append( NRPN.CVM_NM_VIBRATO_CONFIG, (byte)vibrato_type, bVibratoDuration, true ); + add.append( NRPN.CVM_NM_VIBRATO_DELAY, bVibratoDelay, true ); } string[] spl = ve.ID.LyricHandle.L0.getPhoneticSymbolList(); @@ -2046,23 +2070,23 @@ namespace Boare.Lib.Vsq { } char[] symbols = s.ToCharArray(); if ( renderer.StartsWith( "DSB2" ) ) { - add.append( 0x5011, (byte)0x01 );//TODO: 0x5011の意味は解析中 + add.append( 0x5011, (byte)0x01, true );//TODO: 0x5011の意味は解析中 } - add.append( NRPN.CVM_NM_PHONETIC_SYMBOL_BYTES, (byte)symbols.Length );// 0x12(Number of phonetic symbols in bytes) + add.append( NRPN.CVM_NM_PHONETIC_SYMBOL_BYTES, (byte)symbols.Length, true );// 0x12(Number of phonetic symbols in bytes) int count = -1; for ( int j = 0; j < spl.Length; j++ ) { char[] chars = spl[j].ToCharArray(); for ( int k = 0; k < chars.Length; k++ ) { count++; if ( k == 0 ) { - add.append( (ushort)((0x50 << 8) | (byte)(0x13 + count)), (byte)chars[k], (byte)ve.ID.LyricHandle.L0.getConsonantAdjustment()[j] ); // Phonetic symbol j + add.append( (ushort)((0x50 << 8) | (byte)(0x13 + count)), (byte)chars[k], (byte)ve.ID.LyricHandle.L0.getConsonantAdjustment()[j], true ); // Phonetic symbol j } else { - add.append( (ushort)((0x50 << 8) | (byte)(0x13 + count)), (byte)chars[k] ); // Phonetic symbol j + add.append( (ushort)((0x50 << 8) | (byte)(0x13 + count)), (byte)chars[k], true ); // Phonetic symbol j } } } if ( !renderer.StartsWith( "DSB2" ) ) { - add.append( NRPN.CVM_NM_PHONETIC_SYMBOL_CONTINUATION, 0x7f ); // End of phonetic symbols + add.append( NRPN.CVM_NM_PHONETIC_SYMBOL_CONTINUATION, 0x7f, true ); // End of phonetic symbols } if ( renderer.StartsWith( "DSB3" ) ) { int v1mean = ve.ID.PMBendDepth * 60 / 100; @@ -2074,18 +2098,19 @@ namespace Boare.Lib.Vsq { } int d1mean = (int)(0.3196 * ve.ID.PMBendLength + 8.0); int d2mean = (int)(0.92 * ve.ID.PMBendLength + 28.0); - add.append( NRPN.CVM_NM_V1MEAN, (byte)v1mean );// 0x50(v1mean) - add.append( NRPN.CVM_NM_D1MEAN, (byte)d1mean );// 0x51(d1mean) - add.append( NRPN.CVM_NM_D1MEAN_FIRST_NOTE, 0x14 );// 0x52(d1meanFirstNote) - add.append( NRPN.CVM_NM_D2MEAN, (byte)d2mean );// 0x53(d2mean) - add.append( NRPN.CVM_NM_D4MEAN, 0x18 );// 0x54(d4mean) - add.append( NRPN.CVM_NM_PMEAN_ONSET_FIRST_NOTE, 0x0a ); // 055(pMeanOnsetFirstNote) - add.append( NRPN.CVM_NM_VMEAN_NOTE_TRNSITION, 0x0c ); // 0x56(vMeanNoteTransition) - add.append( NRPN.CVM_NM_PMEAN_ENDING_NOTE, 0x0c );// 0x57(pMeanEndingNote) - add.append( NRPN.CVM_NM_ADD_PORTAMENTO, (byte)ve.ID.PMbPortamentoUse );// 0x58(AddScoopToUpInternals&AddPortamentoToDownIntervals) - add.append( NRPN.CVM_NM_CHANGE_AFTER_PEAK, 0x32 );// 0x59(changeAfterPeak) + add.append( NRPN.CVM_NM_V1MEAN, (byte)v1mean, true );// 0x50(v1mean) + add.append( NRPN.CVM_NM_D1MEAN, (byte)d1mean, true );// 0x51(d1mean) + add.append( NRPN.CVM_NM_D1MEAN_FIRST_NOTE, 0x14, true );// 0x52(d1meanFirstNote) + add.append( NRPN.CVM_NM_D2MEAN, (byte)d2mean, true );// 0x53(d2mean) + add.append( NRPN.CVM_NM_D4MEAN, (byte)ve.ID.d4mean, true );// 0x54(d4mean) + add.append( NRPN.CVM_NM_PMEAN_ONSET_FIRST_NOTE, (byte)ve.ID.pMeanOnsetFirstNote, true ); // 055(pMeanOnsetFirstNote) + add.append( NRPN.CVM_NM_VMEAN_NOTE_TRNSITION, (byte)ve.ID.vMeanNoteTransition, true ); // 0x56(vMeanNoteTransition) + add.append( NRPN.CVM_NM_PMEAN_ENDING_NOTE, (byte)ve.ID.pMeanEndingNote, true );// 0x57(pMeanEndingNote) + add.append( NRPN.CVM_NM_ADD_PORTAMENTO, (byte)ve.ID.PMbPortamentoUse, true );// 0x58(AddScoopToUpInternals&AddPortamentoToDownIntervals) + byte decay = (byte)(ve.ID.DEMdecGainRate / 100.0 * 0x64); + add.append( NRPN.CVM_NM_CHANGE_AFTER_PEAK, decay, true );// 0x59(changeAfterPeak) byte accent = (byte)(0x64 * ve.ID.DEMaccent / 100.0); - add.append( NRPN.CVM_NM_ACCENT, accent );// 0x5a(Accent) + add.append( NRPN.CVM_NM_ACCENT, accent, true );// 0x5a(Accent) } if ( renderer.StartsWith( "UTU0" ) ) { // エンベロープ @@ -2097,11 +2122,7 @@ namespace Boare.Lib.Vsq { env = new UstEnvelope(); } int[] vals = null; - if ( env.Separator == "" ) { - vals = new int[7]; - } else { vals = new int[10]; - } vals[0] = env.p1; vals[1] = env.p2; vals[2] = env.p3; @@ -2109,11 +2130,9 @@ namespace Boare.Lib.Vsq { vals[4] = env.v2; vals[5] = env.v3; vals[6] = env.v4; - if ( env.Separator != "" ) { - vals[7] = env.p4; - vals[8] = env.p5; - vals[9] = env.v5; - } + vals[7] = env.p4; + vals[8] = env.p5; + vals[9] = env.v5; for ( int i = 0; i < vals.Length; i++ ) { //(value3.msb & 0xf) << 28 | (value2.msb & 0x7f) << 21 | (value2.lsb & 0x7f) << 14 | (value1.msb & 0x7f) << 7 | (value1.lsb & 0x7f) byte msb, lsb; @@ -2165,7 +2184,7 @@ namespace Boare.Lib.Vsq { } } } - add.append( NRPN.CVM_NM_NOTE_MESSAGE_CONTINUATION, 0x7f );// 0x7f(Note message continuation) + add.append( NRPN.CVM_NM_NOTE_MESSAGE_CONTINUATION, 0x7f, true );// 0x7f(Note message continuation) return add; } @@ -2395,8 +2414,8 @@ namespace Boare.Lib.Vsq { NRPN.CC_VD_VERSION_AND_DEVICE, 0x00, 0x00 ); - add2.append( NRPN.CC_VD_DELAY, delay0, delay1 ); - add2.append( NRPN.CC_VD_VIBRATO_DEPTH, (byte)ve.ID.VibratoHandle.StartDepth ); + add2.append( NRPN.CC_VD_DELAY, delay0, delay1, true ); + add2.append( NRPN.CC_VD_VIBRATO_DEPTH, (byte)ve.ID.VibratoHandle.StartDepth, true ); add2.append( NRPN.CC_VR_VIBRATO_RATE, (byte)ve.ID.VibratoHandle.StartRate ); ret.Add( add2 ); int vlength = ve.ID.Length - ve.ID.VibratoDelay; @@ -2456,7 +2475,7 @@ namespace Boare.Lib.Vsq { VsqNrpn add = new VsqNrpn( c, NRPN.VCP_VOICE_CHANGE_PARAMETER_ID, lsb ); - add.append( NRPN.VCP_VOICE_CHANGE_PARAMETER, (byte)vbpl.getElement( j ) ); + add.append( NRPN.VCP_VOICE_CHANGE_PARAMETER, (byte)vbpl.getElement( j ), true ); res.Add( add ); } } @@ -2565,11 +2584,11 @@ namespace Boare.Lib.Vsq { long last = 0; foreach ( MidiEvent me in events ) { #if DEBUG - Console.WriteLine( "me.Clock=" + me.Clock ); + Console.WriteLine( "me.Clock=" + me.clock ); #endif - writeFlexibleLengthUnsignedLong( fs, (ulong)(me.Clock - last) ); + writeFlexibleLengthUnsignedLong( fs, (ulong)(me.clock - last) ); me.writeData( fs ); - last = me.Clock; + last = me.clock; } //WriteFlexibleLengthUnsignedLong( fs, (ulong)(last_clock + 120 - last) ); diff --git a/trunk/Boare.Lib.Vsq/VsqMetaText/Handle.cs b/trunk/Boare.Lib.Vsq/VsqMetaText/Handle.cs index 7c25b3b..6515e21 100644 --- a/trunk/Boare.Lib.Vsq/VsqMetaText/Handle.cs +++ b/trunk/Boare.Lib.Vsq/VsqMetaText/Handle.cs @@ -113,6 +113,10 @@ namespace Boare.Lib.Vsq { DepthBP = new VibratoBPList(); } + /*public static VibratoHandle[] fromVED( string ved_file, int original ){ + + }*/ + public object Clone() { VibratoHandle result = new VibratoHandle(); result.Index = Index; diff --git a/trunk/Boare.Lib.Vsq/VsqMetaText/ID.cs b/trunk/Boare.Lib.Vsq/VsqMetaText/ID.cs index 5b9f171..f65327b 100644 --- a/trunk/Boare.Lib.Vsq/VsqMetaText/ID.cs +++ b/trunk/Boare.Lib.Vsq/VsqMetaText/ID.cs @@ -23,11 +23,12 @@ namespace Boare.Lib.Vsq { /// [Serializable] public class VsqID : ICloneable { + public const int MAX_NOTE_LENGTH = 16383; internal int value; public VsqIDType type; internal int IconHandle_index; public IconHandle IconHandle; - public int Length; + private int m_length; public int Note; public int Dynamics; public int PMBendDepth; @@ -42,9 +43,28 @@ namespace Boare.Lib.Vsq { public int VibratoDelay; internal int NoteHeadHandle_index; public NoteHeadHandle NoteHeadHandle; + public int pMeanOnsetFirstNote = 0x0a; + public int vMeanNoteTransition = 0x0c; + public int d4mean = 0x18; + public int pMeanEndingNote = 0x0c; public static VsqID EOS = new VsqID( -1 ); + public int Length { + get { + return m_length; + } + set { + if ( value < 0 ) { + m_length = 0; + } else if ( MAX_NOTE_LENGTH < value ) { + m_length = MAX_NOTE_LENGTH; + } else { + m_length = value; + } + } + } + /// /// このインスタンスの簡易コピーを取得します。 /// @@ -63,6 +83,10 @@ namespace Boare.Lib.Vsq { result.PMbPortamentoUse = this.PMbPortamentoUse; result.DEMdecGainRate = this.DEMdecGainRate; result.DEMaccent = this.DEMaccent; + result.d4mean = this.d4mean; + result.pMeanOnsetFirstNote = this.pMeanOnsetFirstNote; + result.vMeanNoteTransition = this.vMeanNoteTransition; + result.pMeanEndingNote = this.pMeanEndingNote; if ( this.LyricHandle != null ) { result.LyricHandle = (LyricHandle)this.LyricHandle.Clone(); } diff --git a/trunk/Boare.Lib.Vsq/VsqMetaText/VsqMetaText.cs b/trunk/Boare.Lib.Vsq/VsqMetaText/VsqMetaText.cs index 57362fd..c59d1ff 100644 --- a/trunk/Boare.Lib.Vsq/VsqMetaText/VsqMetaText.cs +++ b/trunk/Boare.Lib.Vsq/VsqMetaText/VsqMetaText.cs @@ -845,15 +845,15 @@ namespace Boare.Lib.Vsq { } public static bool test( string fpath ) { - VsqMetaText metaText; + /*VsqMetaText metaText; using ( TextMemoryStream sr = new TextMemoryStream( fpath, Encoding.Unicode ) ) { metaText = new VsqMetaText( sr ); - } + }*/ string result = "test.txt"; StreamReader honmono = new StreamReader( fpath ); - TextMemoryStream copy = new TextMemoryStream( FileAccess.ReadWrite ); - metaText.print( copy, true, 1000, 100 ); + TextMemoryStream copy = new TextMemoryStream(); + //metaText.print( copy, true, 1000, 100 ); copy.rewind(); while ( honmono.Peek() >= 0 && copy.peek() >= 0 ) { string hon = honmono.ReadLine(); diff --git a/trunk/Boare.Lib.Vsq/VsqNrpn.cs b/trunk/Boare.Lib.Vsq/VsqNrpn.cs index 56a66a4..fadac7d 100644 --- a/trunk/Boare.Lib.Vsq/VsqNrpn.cs +++ b/trunk/Boare.Lib.Vsq/VsqNrpn.cs @@ -22,6 +22,7 @@ namespace Boare.Lib.Vsq { public byte DataMsb; public byte DataLsb; public bool DataLsbSpecified; + public bool msbOmitRequired; private List m_list; public VsqNrpn( int clock, ushort nrpn, byte data_msb ) { @@ -30,6 +31,7 @@ namespace Boare.Lib.Vsq { DataMsb = data_msb; DataLsb = 0x0; DataLsbSpecified = false; + msbOmitRequired = false; m_list = new List(); } @@ -39,15 +41,20 @@ namespace Boare.Lib.Vsq { DataMsb = data_msb; DataLsb = data_lsb; DataLsbSpecified = true; + msbOmitRequired = false; m_list = new List(); } public VsqNrpn[] expand() { List ret = new List(); if ( DataLsbSpecified ) { - ret.Add( new VsqNrpn( Clock, Nrpn, DataMsb, DataLsb ) ); + VsqNrpn v = new VsqNrpn( Clock, Nrpn, DataMsb, DataLsb ); + v.msbOmitRequired = msbOmitRequired; + ret.Add( v ); } else { - ret.Add( new VsqNrpn( Clock, Nrpn, DataMsb ) ); + VsqNrpn v = new VsqNrpn( Clock, Nrpn, DataMsb ); + v.msbOmitRequired = msbOmitRequired; + ret.Add( v ); } for ( int i = 0; i < m_list.Count; i++ ) { ret.AddRange( m_list[i].expand() ); @@ -123,21 +130,24 @@ namespace Boare.Lib.Vsq { if ( source[0].DataLsbSpecified ) { ret.Add( new NrpnData( source[0].Clock, 0x26, source[0].DataLsb ) ); } - byte last_msb = msb; for ( int i = 1; i < source.Length; i++ ) { - ushort tnrpn = (ushort)source[i].Nrpn; + VsqNrpn item = source[i]; + ushort tnrpn = item.Nrpn; msb = (byte)(tnrpn >> 8); lsb = (byte)(tnrpn - (tnrpn << 8)); - //if ( msb != last_msb ) { - ret.Add( new NrpnData( source[i].Clock, 0x63, msb ) ); - //} else if ( msb == 0x63 ) { - // ret.Add( new NrpnData( source[i].Clock, 0x63, msb ) ); - //} - last_msb = msb; - ret.Add( new NrpnData( source[i].Clock, 0x62, lsb ) ); - ret.Add( new NrpnData( source[i].Clock, 0x06, source[i].DataMsb ) ); - if ( source[i].DataLsbSpecified ) { - ret.Add( new NrpnData( source[i].Clock, 0x26, source[i].DataLsb ) ); + if ( item.msbOmitRequired ) { + ret.Add( new NrpnData( item.Clock, 0x62, lsb ) ); + ret.Add( new NrpnData( item.Clock, 0x06, item.DataMsb ) ); + if ( item.DataLsbSpecified ) { + ret.Add( new NrpnData( item.Clock, 0x26, item.DataLsb ) ); + } + } else { + ret.Add( new NrpnData( item.Clock, 0x63, msb ) ); + ret.Add( new NrpnData( item.Clock, 0x62, lsb ) ); + ret.Add( new NrpnData( item.Clock, 0x06, item.DataMsb ) ); + if ( item.DataLsbSpecified ) { + ret.Add( new NrpnData( item.Clock, 0x26, item.DataLsb ) ); + } } } return ret.ToArray(); @@ -154,6 +164,18 @@ namespace Boare.Lib.Vsq { public void append( ushort nrpn, byte data_msb, byte data_lsb ) { m_list.Add( new VsqNrpn( Clock, nrpn, data_msb, data_lsb ) ); } + + public void append( ushort nrpn, byte data_msb, bool msb_omit_required ) { + VsqNrpn v = new VsqNrpn( Clock, nrpn, data_msb ); + v.msbOmitRequired = msb_omit_required; + m_list.Add( v ); + } + + public void append( ushort nrpn, byte data_msb, byte data_lsb, bool msb_omit_required ) { + VsqNrpn v = new VsqNrpn( Clock, nrpn, data_msb, data_lsb ); + v.msbOmitRequired = msb_omit_required; + m_list.Add( v ); + } } } diff --git a/trunk/Boare.Lib.Vsq/VsqTrack.cs b/trunk/Boare.Lib.Vsq/VsqTrack.cs index f1cb308..b3b15a3 100644 --- a/trunk/Boare.Lib.Vsq/VsqTrack.cs +++ b/trunk/Boare.Lib.Vsq/VsqTrack.cs @@ -131,6 +131,18 @@ namespace Boare.Lib.Vsq { } } + /// + /// ピッチベンド。Cent単位 + /// + /// + /// + public double getPitchAt( int clock ) { + double inv2_13 = 1.0 / 8192.0; + int pit = MetaText.PIT.getValue( clock ); + int pbs = MetaText.PBS.getValue( clock ); + return (double)pit * (double)pbs * inv2_13 * 100.0; + } + public void sortEvent() { MetaText.Events.sort(); } @@ -171,7 +183,7 @@ namespace Boare.Lib.Vsq { /// /// public void printMetaText( string file ) { - TextMemoryStream tms = new TextMemoryStream( FileAccess.ReadWrite ); + TextMemoryStream tms = new TextMemoryStream(); int count = MetaText.getEventList().getCount(); int clLast = MetaText.getEventList().getElement( count - 1 ).Clock + 480; MetaText.print( tms, true, clLast, 0 ); @@ -278,6 +290,10 @@ namespace Boare.Lib.Vsq { return MetaText.getEventList().getElement( index ); } + public VsqEvent findEventFromID( int internal_id ) { + return MetaText.getEventList().findFromID( internal_id ); + } + public void setEvent( int index, VsqEvent item ) { MetaText.getEventList().setElement( index, item ); } @@ -390,21 +406,30 @@ namespace Boare.Lib.Vsq { #endif using ( TextMemoryStream sw = new TextMemoryStream() ) { for ( int i = 0; i < midi_event.Count; i++ ) { - if ( midi_event[i].FirstByte == 0xff && midi_event[i].Data.Length > 0 ) { + if ( midi_event[i].firstByte == 0xff && midi_event[i].data.Length > 0 ) { // meta textを抽出 - byte type = midi_event[i].Data[0]; + byte type = midi_event[i].data[0]; if ( type == 0x01 || type == 0x03 ) { - char[] ch = new char[midi_event[i].Data.Length - 1]; - for ( int j = 1; j < midi_event[i].Data.Length; j++ ) { - ch[j - 1] = (char)midi_event[i].Data[j]; + char[] ch = new char[midi_event[i].data.Length - 1]; + for ( int j = 1; j < midi_event[i].data.Length; j++ ) { + ch[j - 1] = (char)midi_event[i].data[j]; } string line = new string( ch ); if ( type == 0x01 ) { int second_colon = line.IndexOf( ':', 3 ); line = line.Substring( second_colon + 1 ); - line = line.Replace( "\\n", Environment.NewLine ); - line = line.Replace( "\n", Environment.NewLine ); - sw.write( line ); + line = line.Replace( "\\n", "\n" ); + //line = line.Replace( "\n", Environment.NewLine ); + string[] lines = line.Split( '\n' ); + int c = lines.Length; + for ( int j = 0; j < c; j++ ) { + if ( j < c - 1 ) { + sw.writeLine( lines[j] ); + } else { + sw.write( lines[j] ); + } + } + //sw.write( line ); } else { Name = line; } diff --git a/trunk/Boare.Lib.Vsq/VsqVoiceLanguage.cs b/trunk/Boare.Lib.Vsq/VsqVoiceLanguage.cs new file mode 100644 index 0000000..8916e77 --- /dev/null +++ b/trunk/Boare.Lib.Vsq/VsqVoiceLanguage.cs @@ -0,0 +1,34 @@ +/* + * VsqVoiceLanguage.cs + * Copyright (c) 2008-2009 kbinani + * + * This file is part of Boare.Lib.Vsq. + * + * Boare.Lib.Vsq is free software; you can redistribute it and/or + * modify it under the terms of the BSD License. + * + * Boare.Lib.Vsq 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. + */ +namespace Boare.Lib.Vsq { + + /// + /// Represents the voice language of singer. + /// + public enum VsqVoiceLanguage : int { + /// + /// Default value, equivalent to "Japanese". + /// + Default = 0, + /// + /// Japanese + /// + Japanese = 0, + /// + /// English + /// + English = 1, + } + +}