/* * VsqFile.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. */ #define NEW_IMPL #if JAVA package org.kbinani.vsq; import java.util.*; import java.io.*; import org.kbinani.*; #else using System; using bocoree; using bocoree.java.util; using bocoree.java.io; namespace Boare.Lib.Vsq { using boolean = System.Boolean; using Integer = Int32; using Long = System.Int64; #endif /// /// VSQファイルの内容を保持するクラス /// #if JAVA public class VsqFile implements Cloneable, Serializable{ #else [Serializable] public class VsqFile : ICloneable { #endif /// /// トラックのリスト.最初のトラックはMasterTrackであり,通常の音符が格納されるトラックはインデックス1以降となる /// public Vector Track; /// /// テンポ情報を保持したテーブル /// public Vector TempoTable; public Vector TimesigTable; protected int m_tpq; /// /// 曲の長さを取得します。(クロック(4分音符は480クロック)) /// public int TotalClocks = 0; protected int m_base_tempo; public VsqMaster Master; // VsqMaster, VsqMixerは通常,最初の非Master Trackに記述されるが,可搬性のため, public VsqMixer Mixer; // ここではVsqFileに直属するものとして取り扱う. public Object Tag; static readonly byte[] _MTRK = new byte[] { (byte)0x4d, (byte)0x54, (byte)0x72, (byte)0x6b }; static readonly byte[] _MTHD = new byte[] { (byte)0x4d, (byte)0x54, (byte)0x68, (byte)0x64 }; static readonly byte[] _MASTER_TRACK = new byte[] { (byte)0x4D, (byte)0x61, (byte)0x73, (byte)0x74, (byte)0x65, (byte)0x72, (byte)0x20, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x6B, }; static readonly String[] _CURVES = new String[] { "VEL", "DYN", "BRE", "BRI", "CLE", "OPE", "GEN", "POR", "PIT", "PBS" }; #if JAVA public VsqFile( UstFile ust ){ this( "Miku", 1, 4, 4, ust.getBaseTempo() ); #else public VsqFile( UstFile ust ) : this( "Miku", 1, 4, 4, ust.getBaseTempo() ) { #endif int clock_count = 480 * 4; //pre measure = 1、4分の4拍子としたので VsqBPList pitch = new VsqBPList( 0, -2400, 2400 ); // ノートナンバー×100 for ( Iterator itr = ust.getTrack( 0 ).getNoteEventIterator(); itr.hasNext(); ) { UstEvent ue = (UstEvent)itr.next(); if ( ue.Lyric != "R" ) { VsqID id = new VsqID( 0 ); id.setLength( ue.getLength() ); ByRef psymbol = new ByRef( "a" ); if ( !SymbolTable.attatch( ue.Lyric, psymbol ) ) { psymbol.value = "a"; } id.LyricHandle = new LyricHandle( ue.Lyric, psymbol.value ); id.Note = ue.Note; id.type = VsqIDType.Anote; VsqEvent ve = new VsqEvent( clock_count, id ); ve.UstEvent = (UstEvent)ue.clone(); Track.get( 1 ).addEvent( ve ); if ( ue.Pitches != null ) { // PBTypeクロックごとにデータポイントがある int clock = clock_count - ue.PBType; for ( int i = 0; i < ue.Pitches.Length; i++ ) { clock += ue.PBType; pitch.add( clock, (int)ue.Pitches[i] ); } } } if ( ue.Tempo > 0.0f ) { TempoTable.add( new TempoTableEntry( clock_count, (int)(60e6 / ue.Tempo), 0.0 ) ); } clock_count += ue.getLength(); } updateTempoInfo(); updateTotalClocks(); updateTimesigInfo(); reflectPitch( this, 1, pitch ); } /// /// master==MasterPitchControl.Pitchの場合、m_pitchからPITとPBSを再構成。 /// master==MasterPitchControl.PITandPBSの場合、PITとPBSからm_pitchを再構成 /// private static void reflectPitch( VsqFile vsq, int track, VsqBPList pitch ) { //double offset = AttachedCurves[track - 1].MasterTuningInCent * 100; //Vector keyclocks = new Vector( pitch.getKeys() ); int keyclock_size = pitch.size(); VsqBPList pit = new VsqBPList( 0, -8192, 8191 ); VsqBPList pbs = new VsqBPList( 2, 0, 24 ); int premeasure_clock = vsq.getPreMeasureClocks(); int lastpit = pit.getDefault(); int lastpbs = pbs.getDefault(); int vpbs = 24; int vpit = 0; Vector parts = new Vector(); // 連続した音符ブロックの先頭音符のクロック位置。のリスト parts.add( premeasure_clock ); int lastclock = premeasure_clock; for ( Iterator itr = vsq.Track.get( track ).getNoteEventIterator(); itr.hasNext(); ) { VsqEvent ve = (VsqEvent)itr.next(); if ( ve.Clock <= lastclock ) { lastclock = Math.Max( lastclock, ve.Clock + ve.ID.getLength() ); } else { parts.add( ve.Clock ); lastclock = ve.Clock + ve.ID.getLength(); } } int parts_size = parts.size(); for ( int i = 0; i < parts_size; i++ ) { int partstart = parts.get( i ); int partend = int.MaxValue; if ( i + 1 < parts.size() ) { partend = parts.get( i + 1 ); } // まず、区間内の最大ピッチベンド幅を調べる double max = 0; for ( int j = 0; j < keyclock_size; j++ ) { int clock = pitch.getKeyClock( j ); if ( clock < partstart ) { continue; } if ( partend <= clock ) { break; } max = Math.Max( max, Math.Abs( pitch.getValue( clock ) / 100.0 ) ); } // 最大ピッチベンド幅を表現できる最小のPBSを計算 vpbs = (int)(Math.Ceiling( max * 8192.0 / 8191.0 ) + 0.1); if ( vpbs <= 0 ) { vpbs = 1; } double pitch2 = pitch.getValue( partstart ) / 100.0; if ( lastpbs != vpbs ) { pbs.add( partstart, vpbs ); lastpbs = vpbs; } vpit = (int)(pitch2 * 8192 / (double)vpbs); if ( lastpit != vpit ) { pit.add( partstart, vpit ); lastpit = vpit; } for ( int j = 0; j < keyclock_size; j++ ) { int clock = pitch.getKeyClock( j ); if ( clock < partstart ) { continue; } if ( partend <= clock ) { break; } if ( clock != partstart ) { pitch2 = pitch.getElement( j ) / 100.0; vpit = (int)(pitch2 * 8192 / (double)vpbs); if ( lastpit != vpit ) { pit.add( clock, vpit ); lastpit = vpit; } } } } vsq.Track.get( track ).setCurve( "pit", pit ); vsq.Track.get( track ).setCurve( "pbs", pbs ); } /// /// プリセンドタイムの妥当性を判定します /// /// /// public boolean checkPreSendTimeValidity( int ms_pre_send_time ) { int track_count = Track.size(); for ( int i = 1; i < track_count; i++ ) { VsqTrack track = Track.get( i ); for ( Iterator itr = track.getNoteEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); int presend_clock = getPresendClockAt( item.Clock, ms_pre_send_time ); if ( item.Clock - presend_clock < 0 ) { return false; } break; } } return true; } /// /// テンポ値を一律order倍します。 /// /// public void speedingUp( double order ) { lock ( TempoTable ) { int c = TempoTable.size(); for ( int i = 0; i < c; i++ ) { TempoTable.get( i ).Tempo = (int)(TempoTable.get( i ).Tempo / order); } } updateTempoInfo(); } /// /// このインスタンスに編集を行うコマンドを実行します /// /// 実行するコマンド /// 編集結果を元に戻すためのコマンドを返します public VsqCommand executeCommand( VsqCommand command ) { #if DEBUG PortUtil.println( "VsqFile.Execute(VsqCommand)" ); PortUtil.println( " type=" + command.Type ); #endif VsqCommandType type = command.Type; if ( type == VsqCommandType.CHANGE_PRE_MEASURE ) { #region CHANGE_PRE_MEASURE VsqCommand ret = VsqCommand.generateCommandChangePreMeasure( Master.PreMeasure ); int value = (Integer)command.Args[0]; Master.PreMeasure = value; updateTimesigInfo(); return ret; #endregion } else if ( type == VsqCommandType.TRACK_ADD ) { #region TRACK_ADD #if DEBUG System.Diagnostics.Debug.WriteLine( " AddTrack" ); #endif VsqTrack track = (VsqTrack)command.Args[0]; VsqMixerEntry mixer = (VsqMixerEntry)command.Args[1]; int position = (Integer)command.Args[2]; VsqCommand ret = VsqCommand.generateCommandDeleteTrack( position ); if ( Track.size() <= 17 ) { Track.insertElementAt( (VsqTrack)track.clone(), position ); Mixer.Slave.add( (VsqMixerEntry)mixer.clone() ); return ret; } else { return null; } #endregion } else if ( type == VsqCommandType.TRACK_DELETE ) { #region TRACK_DELETE int track = (Integer)command.Args[0]; VsqCommand ret = VsqCommand.generateCommandAddTrack( Track.get( track ), Mixer.Slave.get( track - 1 ), track ); Track.removeElementAt( track ); Mixer.Slave.removeElementAt( track - 1 ); updateTotalClocks(); return ret; #endregion } else if ( type == VsqCommandType.UPDATE_TEMPO ) { #region UPDATE_TEMPO int clock = (Integer)command.Args[0]; int tempo = (Integer)command.Args[1]; int new_clock = (Integer)command.Args[2]; int index = -1; int c = TempoTable.size(); for ( int i = 0; i < c; i++ ) { if ( TempoTable.get( i ).Clock == clock ) { index = i; break; } } VsqCommand ret = null; if ( index >= 0 ) { if ( tempo <= 0 ) { ret = VsqCommand.generateCommandUpdateTempo( clock, clock, TempoTable.get( index ).Tempo ); TempoTable.removeElementAt( index ); } else { ret = VsqCommand.generateCommandUpdateTempo( new_clock, clock, TempoTable.get( index ).Tempo ); TempoTable.get( index ).Tempo = tempo; TempoTable.get( index ).Clock = new_clock; } } else { ret = VsqCommand.generateCommandUpdateTempo( clock, clock, -1 ); TempoTable.add( new TempoTableEntry( new_clock, tempo, 0.0 ) ); } updateTempoInfo(); updateTotalClocks(); // 編集領域を更新 int affected_clock = Math.Min( clock, new_clock ); c = Track.size(); for ( int i = 1; i < c; i++ ) { if ( affected_clock < Track.get( i ).getEditedStart() ) { Track.get( i ).setEditedStart( affected_clock ); } Track.get( i ).setEditedEnd( (int)TotalClocks ); } return ret; #endregion } else if ( type == VsqCommandType.UPDATE_TEMPO_RANGE ) { #region UPDATE_TEMPO_RANGE int[] clocks = (int[])command.Args[0]; int[] tempos = (int[])command.Args[1]; int[] new_clocks = (int[])command.Args[2]; int[] new_tempos = new int[tempos.Length]; int affected_clock = int.MaxValue; for ( int i = 0; i < clocks.Length; i++ ) { int index = -1; affected_clock = Math.Min( affected_clock, clocks[i] ); affected_clock = Math.Min( affected_clock, new_clocks[i] ); int tempo_table_count = TempoTable.size(); for ( int j = 0; j < tempo_table_count; j++ ) { if ( TempoTable.get( j ).Clock == clocks[i] ) { index = j; break; } } if ( index >= 0 ) { new_tempos[i] = TempoTable.get( index ).Tempo; if ( tempos[i] <= 0 ) { TempoTable.removeElementAt( index ); } else { TempoTable.get( index ).Tempo = tempos[i]; TempoTable.get( index ).Clock = new_clocks[i]; } } else { new_tempos[i] = -1; TempoTable.add( new TempoTableEntry( new_clocks[i], tempos[i], 0.0 ) ); } } updateTempoInfo(); updateTotalClocks(); int track_count = Track.size(); for ( int i = 1; i < track_count; i++ ) { if ( affected_clock < Track.get( i ).getEditedStart() ) { Track.get( i ).setEditedStart( affected_clock ); } Track.get( i ).setEditedEnd( (int)TotalClocks ); } return VsqCommand.generateCommandUpdateTempoRange( new_clocks, clocks, new_tempos ); #endregion } else if ( type == VsqCommandType.UPDATE_TIMESIG ) { #region UPDATE_TIMESIG int barcount = (Integer)command.Args[0]; int numerator = (Integer)command.Args[1]; int denominator = (Integer)command.Args[2]; int new_barcount = (Integer)command.Args[3]; int index = -1; int timesig_table_count = TimesigTable.size(); for ( int i = 0; i < timesig_table_count; i++ ) { if ( barcount == TimesigTable.get( i ).BarCount ) { index = i; break; } } VsqCommand ret = null; if ( index >= 0 ) { if ( numerator <= 0 ) { ret = VsqCommand.generateCommandUpdateTimesig( barcount, barcount, TimesigTable.get( index ).Numerator, TimesigTable.get( index ).Denominator ); TimesigTable.removeElementAt( index ); } else { ret = VsqCommand.generateCommandUpdateTimesig( new_barcount, barcount, TimesigTable.get( index ).Numerator, TimesigTable.get( index ).Denominator ); TimesigTable.get( index ).BarCount = new_barcount; TimesigTable.get( index ).Numerator = numerator; TimesigTable.get( index ).Denominator = denominator; } } else { ret = VsqCommand.generateCommandUpdateTimesig( new_barcount, new_barcount, -1, -1 ); TimesigTable.add( new TimeSigTableEntry( 0, numerator, denominator, new_barcount ) ); } updateTimesigInfo(); updateTotalClocks(); return ret; #endregion } else if ( type == VsqCommandType.UPDATE_TIMESIG_RANGE ) { #region UPDATE_TIMESIG_RANGE int[] barcounts = (int[])command.Args[0]; int[] numerators = (int[])command.Args[1]; int[] denominators = (int[])command.Args[2]; int[] new_barcounts = (int[])command.Args[3]; int[] new_numerators = new int[numerators.Length]; int[] new_denominators = new int[denominators.Length]; for ( int i = 0; i < barcounts.Length; i++ ) { int index = -1; // すでに拍子が登録されているかどうかを検査 int timesig_table_count = TimesigTable.size(); for ( int j = 0; j < timesig_table_count; j++ ) { if ( TimesigTable.get( j ).BarCount == barcounts[i] ) { index = j; break; } } if ( index >= 0 ) { // 登録されている場合 new_numerators[i] = TimesigTable.get( index ).Numerator; new_denominators[i] = TimesigTable.get( index ).Denominator; if ( numerators[i] <= 0 ) { TimesigTable.removeElementAt( index ); } else { TimesigTable.get( index ).BarCount = new_barcounts[i]; TimesigTable.get( index ).Numerator = numerators[i]; TimesigTable.get( index ).Denominator = denominators[i]; } } else { // 登録されていない場合 new_numerators[i] = -1; new_denominators[i] = -1; TimesigTable.add( new TimeSigTableEntry( 0, numerators[i], denominators[i], new_barcounts[i] ) ); } } updateTimesigInfo(); updateTotalClocks(); return VsqCommand.generateCommandUpdateTimesigRange( new_barcounts, barcounts, new_numerators, new_denominators ); #endregion } else if ( type == VsqCommandType.REPLACE ) { #region REPLACE VsqFile vsq = (VsqFile)command.Args[0]; VsqFile inv = (VsqFile)this.clone(); Track.clear(); int track_count = vsq.Track.size(); for ( int i = 0; i < track_count; i++ ) { Track.add( (VsqTrack)vsq.Track.get( i ).clone() ); } TempoTable.clear(); int tempo_table_count = vsq.TempoTable.size(); for ( int i = 0; i < tempo_table_count; i++ ) { TempoTable.add( (TempoTableEntry)vsq.TempoTable.get( i ).clone() ); } TimesigTable.clear(); int timesig_table_count = vsq.TimesigTable.size(); for ( int i = 0; i < timesig_table_count; i++ ) { TimesigTable.add( (TimeSigTableEntry)vsq.TimesigTable.get( i ).clone() ); } m_tpq = vsq.m_tpq; TotalClocks = vsq.TotalClocks; m_base_tempo = vsq.m_base_tempo; Master = (VsqMaster)vsq.Master.clone(); Mixer = (VsqMixer)vsq.Mixer.clone(); updateTotalClocks(); return VsqCommand.generateCommandReplace( inv ); #endregion } else if ( type == VsqCommandType.EVENT_ADD ) { #region EVENT_ADD int track = (Integer)command.Args[0]; VsqEvent item = (VsqEvent)command.Args[1]; Track.get( track ).addEvent( item ); VsqCommand ret = VsqCommand.generateCommandEventDelete( track, item.InternalID ); updateTotalClocks(); if ( item.Clock < Track.get( track ).getEditedStart() ) { Track.get( track ).setEditedStart( item.Clock ); } if ( Track.get( track ).getEditedEnd() < item.Clock + item.ID.getLength() ) { Track.get( track ).setEditedEnd( item.Clock + item.ID.getLength() ); } Track.get( track ).sortEvent(); return ret; #endregion } else if ( type == VsqCommandType.EVENT_ADD_RANGE ) { #region EVENT_ADD_RANGE #if DEBUG PortUtil.println( " TrackAddNoteRange" ); #endif int track = (Integer)command.Args[0]; VsqEvent[] items = (VsqEvent[])command.Args[1]; Vector inv_ids = new Vector(); int min_clock = (int)TotalClocks; int max_clock = 0; VsqTrack target = Track.get( track ); for ( int i = 0; i < items.Length; i++ ) { VsqEvent item = (VsqEvent)items[i].clone(); min_clock = Math.Min( min_clock, item.Clock ); max_clock = Math.Max( max_clock, item.Clock + item.ID.getLength() ); #if DEBUG Console.Write( " i=" + i + "; item.InternalID=" + item.InternalID ); #endif target.addEvent( item ); inv_ids.add( item.InternalID ); #if DEBUG PortUtil.println( " => " + item.InternalID ); #endif } updateTotalClocks(); if ( min_clock < target.getEditedStart() ) { target.setEditedStart( min_clock ); } if ( target.getEditedEnd() < max_clock ) { target.setEditedEnd( max_clock ); } target.sortEvent(); return VsqCommand.generateCommandEventDeleteRange( track, inv_ids ); #endregion } else if ( type == VsqCommandType.EVENT_DELETE ) { #region EVENT_DELETE int track = (Integer)command.Args[0]; int internal_id = (Integer)command.Args[1]; VsqEvent[] original = new VsqEvent[1]; VsqTrack target = Track.get( 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 < target.getEditedStart() ) { target.setEditedStart( original[0].Clock ); } if ( target.getEditedEnd() < original[0].Clock + original[0].ID.getLength() ) { target.setEditedEnd( original[0].Clock + original[0].ID.getLength() ); } VsqCommand ret = VsqCommand.generateCommandEventAddRange( track, original ); int count = target.getEventCount(); for ( int i = 0; i < count; i++ ) { if ( target.getEvent( i ).InternalID == internal_id ) { target.removeEvent( i ); break; } } updateTotalClocks(); return ret; #endregion } else if ( type == VsqCommandType.EVENT_DELETE_RANGE ) { #region EVENT_DELETE_RANGE Vector internal_ids = (Vector)command.Args[1]; int track = (Integer)command.Args[0]; Vector inv = new Vector(); int min_clock = int.MaxValue; int max_clock = int.MinValue; VsqTrack target = this.Track.get( track ); int count = internal_ids.size(); for ( int j = 0; j < count; j++ ) { for ( int i = 0; i < target.getEventCount(); i++ ) { VsqEvent item = target.getEvent( i ); if ( internal_ids.get( 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.getLength() ); target.removeEvent( i ); break; } } } updateTotalClocks(); target.setEditedStart( min_clock ); target.setEditedEnd( max_clock ); return VsqCommand.generateCommandEventAddRange( track, inv.toArray( new VsqEvent[] { } ) ); #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_CLOCK ) { #region EVENT_CHANGE_CLOCK int track = (Integer)command.Args[0]; int internal_id = (Integer)command.Args[1]; int value = (Integer)command.Args[2]; VsqTrack target = this.Track.get( 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.getLength(), value + item.ID.getLength() ); target.setEditedStart( min ); target.setEditedEnd( max ); item.Clock = value; updateTotalClocks(); target.sortEvent(); return ret; } } return null; #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_LYRIC ) { #region EVENT_CHANGE_LYRIC int track = (Integer)command.Args[0]; int internal_id = (Integer)command.Args[1]; String phrase = (String)command.Args[2]; String phonetic_symbol = (String)command.Args[3]; boolean protect_symbol = (Boolean)command.Args[4]; VsqTrack target = this.Track.get( track ); for ( Iterator itr = target.getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_id ) { if ( item.ID.type == VsqIDType.Anote ) { VsqCommand ret = VsqCommand.generateCommandEventChangeLyric( track, internal_id, item.ID.LyricHandle.L0.Phrase, item.ID.LyricHandle.L0.getPhoneticSymbol(), item.ID.LyricHandle.L0.PhoneticSymbolProtected ); item.ID.LyricHandle.L0.Phrase = phrase; item.ID.LyricHandle.L0.setPhoneticSymbol( phonetic_symbol ); item.ID.LyricHandle.L0.PhoneticSymbolProtected = protect_symbol; target.setEditedStart( item.Clock ); target.setEditedEnd( item.Clock + item.ID.getLength() ); updateTotalClocks(); return ret; } } } return null; #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_NOTE ) { #region EVENT_CHANGE_NOTE int track = (Integer)command.Args[0]; int internal_id = (Integer)command.Args[1]; int note = (Integer)command.Args[2]; VsqTrack target = this.Track.get( 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(); target.setEditedStart( item.Clock ); target.setEditedEnd( item.Clock + item.ID.getLength() ); return ret; } } return null; #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_CLOCK_AND_NOTE ) { #region EVENT_CHANGE_CLOCK_AND_NOTE int track = (Integer)command.Args[0]; int internal_id = (Integer)command.Args[1]; int clock = (Integer)command.Args[2]; int note = (Integer)command.Args[3]; VsqTrack target = this.Track.get( 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.getLength(), clock + item.ID.getLength() ); target.setEditedStart( min ); target.setEditedEnd( max ); item.Clock = clock; item.ID.Note = note; target.sortEvent(); updateTotalClocks(); return ret; } } return null; #endregion } else if ( type == VsqCommandType.TRACK_CURVE_EDIT ) { #region TRACK_CURVE_EDIT int track = (Integer)command.Args[0]; String curve = (String)command.Args[1]; Vector com = (Vector)command.Args[2]; VsqCommand inv = null; Vector edit = new Vector(); VsqBPList target_list = Track.get( track ).getCurve( curve ); if ( com != null ) { if ( com.size() > 0 ) { int start_clock = com.get( 0 ).Clock; int end_clock = com.get( 0 ).Clock; for ( Iterator itr = com.iterator(); itr.hasNext(); ) { BPPair item = (BPPair)itr.next(); start_clock = Math.Min( start_clock, item.Clock ); end_clock = Math.Max( end_clock, item.Clock ); } Track.get( track ).setEditedStart( start_clock ); Track.get( track ).setEditedEnd( end_clock ); int start_value = target_list.getValue( start_clock ); int end_value = target_list.getValue( end_clock ); for ( Iterator i = target_list.keyClockIterator(); i.hasNext(); ) { int clock = (Integer)i.next(); if ( start_clock <= clock && clock <= end_clock ) { edit.add( new BPPair( clock, target_list.getValue( clock ) ) ); } } boolean start_found = false; boolean end_found = false; int count = edit.size(); for ( int i = 0; i < count; i++ ) { if ( edit.get( i ).Clock == start_clock ) { start_found = true; edit.get( i ).Value = start_value; if ( start_found && end_found ) { break; } } if ( edit.get( i ).Clock == end_clock ) { end_found = true; edit.get( i ).Value = end_value; if ( start_found && end_found ) { break; } } } if ( !start_found ) { edit.add( new BPPair( start_clock, start_value ) ); } if ( !end_found ) { edit.add( new BPPair( end_clock, end_value ) ); } // 並べ替え Collections.sort( edit ); inv = VsqCommand.generateCommandTrackCurveEdit( track, curve, edit ); } else if ( com.size() == 0 ) { inv = VsqCommand.generateCommandTrackCurveEdit( track, curve, new Vector() ); } } updateTotalClocks(); if ( com.size() == 0 ) { return inv; } else if ( com.size() == 1 ) { boolean found = false; for ( Iterator itr = target_list.keyClockIterator(); itr.hasNext(); ) { int clock = (Integer)itr.next(); if ( clock == com.get( 0 ).Clock ) { found = true; target_list.add( clock, com.get( 0 ).Value ); break; } } if ( !found ) { target_list.add( com.get( 0 ).Clock, com.get( 0 ).Value ); } } else { int start_clock = com.get( 0 ).Clock; int end_clock = com.get( com.size() - 1 ).Clock; boolean removed = true; while ( removed ) { removed = false; for ( Iterator itr = target_list.keyClockIterator(); itr.hasNext(); ) { int clock = (Integer)itr.next(); if ( start_clock <= clock && clock <= end_clock ) { target_list.remove( clock ); removed = true; break; } } } for ( Iterator itr = com.iterator(); itr.hasNext(); ) { BPPair item = (BPPair)itr.next(); target_list.add( item.Clock, item.Value ); } } return inv; #endregion } else if ( type == VsqCommandType.TRACK_CURVE_EDIT2 ) { #region TRACK_CURVE_EDIT2 int track = (Integer)command.Args[0]; String curve = (String)command.Args[1]; Vector delete = (Vector)command.Args[2]; TreeMap add = (TreeMap)command.Args[3]; Vector inv_delete = new Vector(); TreeMap inv_add = new TreeMap(); processTrackCurveEdit( track, curve, delete, add, inv_delete, inv_add ); updateTotalClocks(); return VsqCommand.generateCommandTrackCurveEdit2( track, curve, inv_delete, inv_add ); #endregion } else if ( type == VsqCommandType.TRACK_CURVE_EDIT2_ALL ) { #region TRACK_CURVE_EDIT2_ALL int track = (Integer)command.Args[0]; Vector curve = (Vector)command.Args[1]; Vector> delete = (Vector>)command.Args[2]; Vector> add = (Vector>)command.Args[3]; int c = curve.size(); Vector> inv_delete = new Vector>(); Vector> inv_add = new Vector>(); for ( int i = 0; i < c; i++ ) { Vector part_inv_delete = new Vector(); TreeMap part_inv_add = new TreeMap(); processTrackCurveEdit( track, curve.get( i ), delete.get( i ), add.get( i ), part_inv_delete, part_inv_add ); inv_delete.add( part_inv_delete ); inv_add.add( part_inv_add ); } updateTotalClocks(); return VsqCommand.generateCommandTrackCurveEdit2All( track, curve, inv_delete, inv_add ); #endregion } else if ( type == VsqCommandType.TRACK_CURVE_REPLACE ) { #region TRACK_CURVE_REPLACE int track = (Integer)command.Args[0]; String target_curve = (String)command.Args[1]; VsqBPList bplist = (VsqBPList)command.Args[2]; VsqCommand inv = VsqCommand.generateCommandTrackCurveReplace( track, target_curve, Track.get( track ).getCurve( target_curve ) ); Track.get( track ).setCurve( target_curve, bplist ); return inv; #endregion } else if ( type == VsqCommandType.TRACK_CURVE_REPLACE_RANGE ) { #region TRACK_CURVE_REPLACE_RANGE int track = (Integer)command.Args[0]; String[] target_curve = (String[])command.Args[1]; VsqBPList[] bplist = (VsqBPList[])command.Args[2]; VsqBPList[] inv_bplist = new VsqBPList[bplist.Length]; VsqTrack work = Track.get( track ); for ( int i = 0; i < target_curve.Length; i++ ) { inv_bplist[i] = work.getCurve( target_curve[i] ); } VsqCommand inv = VsqCommand.generateCommandTrackCurveReplaceRange( track, target_curve, inv_bplist ); for ( int i = 0; i < target_curve.Length; i++ ) { work.setCurve( target_curve[i], bplist[i] ); } return inv; #endregion } else if ( type == VsqCommandType.TRACK_CURVE_EDIT_RANGE ) { #region TRACK_CURVE_EDIT_RANGE int track = (Integer)command.Args[0]; Vector curves = (Vector)command.Args[1]; Vector> coms = (Vector>)command.Args[2]; Vector> inv_coms = new Vector>(); VsqCommand inv = null; int count = curves.size(); for ( int k = 0; k < count; k++ ) { String curve = curves.get( k ); Vector com = coms.get( k ); //SortedList list = Tracks[track][curve].List; Vector edit = new Vector(); if ( com != null ) { if ( com.size() > 0 ) { int start_clock = com.get( 0 ).Clock; int end_clock = com.get( 0 ).Clock; for ( Iterator itr = com.iterator(); itr.hasNext(); ) { BPPair item = (BPPair)itr.next(); start_clock = Math.Min( start_clock, item.Clock ); end_clock = Math.Max( end_clock, item.Clock ); } Track.get( track ).setEditedStart( start_clock ); Track.get( track ).setEditedEnd( end_clock ); int start_value = Track.get( track ).getCurve( curve ).getValue( start_clock ); int end_value = Track.get( track ).getCurve( curve ).getValue( end_clock ); for ( Iterator itr = Track.get( track ).getCurve( curve ).keyClockIterator(); itr.hasNext(); ) { int clock = (Integer)itr.next(); if ( start_clock <= clock && clock <= end_clock ) { edit.add( new BPPair( clock, Track.get( track ).getCurve( curve ).getValue( clock ) ) ); } } boolean start_found = false; boolean end_found = false; for ( int i = 0; i < edit.size(); i++ ) { if ( edit.get( i ).Clock == start_clock ) { start_found = true; edit.get( i ).Value = start_value; if ( start_found && end_found ) { break; } } if ( edit.get( i ).Clock == end_clock ) { end_found = true; edit.get( i ).Value = end_value; if ( start_found && end_found ) { break; } } } if ( !start_found ) { edit.add( new BPPair( start_clock, start_value ) ); } if ( !end_found ) { edit.add( new BPPair( end_clock, end_value ) ); } // 並べ替え Collections.sort( edit ); inv_coms.add( edit ); //inv = generateCommandTrackEditCurve( track, curve, edit ); } else if ( com.size() == 0 ) { //inv = generateCommandTrackEditCurve( track, curve, new Vector() ); inv_coms.add( new Vector() ); } } updateTotalClocks(); if ( com.size() == 0 ) { return inv; } else if ( com.size() == 1 ) { boolean found = false; for ( Iterator itr = Track.get( track ).getCurve( curve ).keyClockIterator(); itr.hasNext(); ) { int clock = (Integer)itr.next(); if ( clock == com.get( 0 ).Clock ) { found = true; Track.get( track ).getCurve( curve ).add( clock, com.get( 0 ).Value ); break; } } if ( !found ) { Track.get( track ).getCurve( curve ).add( com.get( 0 ).Clock, com.get( 0 ).Value ); } } else { int start_clock = com.get( 0 ).Clock; int end_clock = com.get( com.size() - 1 ).Clock; boolean removed = true; while ( removed ) { removed = false; for ( Iterator itr = Track.get( track ).getCurve( curve ).keyClockIterator(); itr.hasNext(); ) { int clock = (Integer)itr.next(); if ( start_clock <= clock && clock <= end_clock ) { Track.get( track ).getCurve( curve ).remove( clock ); removed = true; break; } } } for ( Iterator itr = com.iterator(); itr.hasNext(); ) { BPPair item = (BPPair)itr.next(); Track.get( track ).getCurve( curve ).add( item.Clock, item.Value ); } } } return VsqCommand.generateCommandTrackCurveEditRange( track, curves, inv_coms ); #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_VELOCITY ) { #region EVENT_CHANGE_VELOCITY int track = (Integer)command.Args[0]; Vector> veloc = (Vector>)command.Args[1]; Vector> inv = new Vector>(); for ( Iterator itr = Track.get( track ).getEventIterator(); itr.hasNext(); ) { VsqEvent ev = (VsqEvent)itr.next(); for ( Iterator itr2 = veloc.iterator(); itr2.hasNext(); ) { ValuePair add = (ValuePair)itr2.next(); if ( ev.InternalID == add.getKey() ) { inv.add( new ValuePair( ev.InternalID, ev.ID.Dynamics ) ); ev.ID.Dynamics = add.getValue(); Track.get( track ).setEditedStart( ev.Clock ); Track.get( track ).setEditedEnd( ev.Clock + ev.ID.getLength() ); break; } } } return VsqCommand.generateCommandEventChangeVelocity( track, inv ); #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_ACCENT ) { #region EVENT_CHANGE_ACCENT int track = (Integer)command.Args[0]; Vector> veloc = (Vector>)command.Args[1]; Vector> inv = new Vector>(); for ( Iterator itr = Track.get( track ).getEventIterator(); itr.hasNext(); ) { VsqEvent ev = (VsqEvent)itr.next(); for ( Iterator itr2 = veloc.iterator(); itr2.hasNext(); ) { ValuePair add = (ValuePair)itr2.next(); if ( ev.InternalID == add.getKey() ) { inv.add( new ValuePair( ev.InternalID, ev.ID.DEMaccent ) ); ev.ID.DEMaccent = add.getValue(); Track.get( track ).setEditedStart( ev.Clock ); Track.get( track ).setEditedEnd( ev.Clock + ev.ID.getLength() ); break; } } } return VsqCommand.generateCommandEventChangeAccent( track, inv ); #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_DECAY ) { #region EVENT_CHANGE_DECAY int track = (Integer)command.Args[0]; Vector> veloc = (Vector>)command.Args[1]; Vector> inv = new Vector>(); for ( Iterator itr = Track.get( track ).getEventIterator(); itr.hasNext(); ) { VsqEvent ev = (VsqEvent)itr.next(); for ( Iterator itr2 = veloc.iterator(); itr2.hasNext(); ) { ValuePair add = (ValuePair)itr2.next(); if ( ev.InternalID == add.getKey() ) { inv.add( new ValuePair( ev.InternalID, ev.ID.DEMdecGainRate ) ); ev.ID.DEMdecGainRate = add.getValue(); Track.get( track ).setEditedStart( ev.Clock ); Track.get( track ).setEditedEnd( ev.Clock + ev.ID.getLength() ); break; } } } return VsqCommand.generateCommandEventChangeDecay( track, inv ); #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_LENGTH ) { #region EVENT_CHANGE_LENGTH int track = (Integer)command.Args[0]; int internal_id = (Integer)command.Args[1]; int new_length = (Integer)command.Args[2]; for ( Iterator itr = Track.get( track ).getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_id ) { VsqCommand ret = VsqCommand.generateCommandEventChangeLength( track, internal_id, item.ID.getLength() ); Track.get( track ).setEditedStart( item.Clock ); int max = Math.Max( item.Clock + item.ID.getLength(), item.Clock + new_length ); Track.get( track ).setEditedEnd( max ); item.ID.setLength( new_length ); updateTotalClocks(); return ret; } } return null; #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_CLOCK_AND_LENGTH ) { #region EVENT_CHANGE_CLOCK_AND_LENGTH int track = (Integer)command.Args[0]; int internal_id = (Integer)command.Args[1]; int new_clock = (Integer)command.Args[2]; int new_length = (Integer)command.Args[3]; for ( Iterator itr = Track.get( track ).getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_id ) { VsqCommand ret = VsqCommand.generateCommandEventChangeClockAndLength( track, internal_id, item.Clock, item.ID.getLength() ); int min = Math.Min( item.Clock, new_clock ); int max_length = Math.Max( item.ID.getLength(), new_length ); int max = Math.Max( item.Clock + max_length, new_clock + max_length ); Track.get( track ).setEditedStart( min ); Track.get( track ).setEditedEnd( max ); item.ID.setLength( new_length ); item.Clock = new_clock; Track.get( track ).sortEvent(); updateTotalClocks(); return ret; } } return null; #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_ID_CONTAINTS ) { #region EVENT_CHANGE_ID_CONTAINTS int track = (Integer)command.Args[0]; int internal_id = (Integer)command.Args[1]; VsqID value = (VsqID)command.Args[2]; for ( Iterator itr = Track.get( track ).getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_id ) { VsqCommand ret = VsqCommand.generateCommandEventChangeIDContaints( track, internal_id, item.ID ); int max_length = Math.Max( item.ID.getLength(), value.getLength() ); Track.get( track ).setEditedStart( item.Clock ); Track.get( track ).setEditedEnd( item.Clock + max_length ); item.ID = (VsqID)value.clone(); if ( item.ID.type == VsqIDType.Singer ) { #if DEBUG PortUtil.println( " EventChangeIDContaints" ); #endif // 歌手変更の場合、次に現れる歌手変更の位置まで編集の影響が及ぶ boolean found = false; for ( Iterator itr2 = Track.get( track ).getSingerEventIterator(); itr2.hasNext(); ) { VsqEvent item2 = (VsqEvent)itr2.next(); if ( item.Clock < item2.Clock ) { Track.get( track ).setEditedEnd( item2.Clock ); found = true; break; } } if ( !found ) { // 変更対象が、該当トラック最後の歌手変更イベントだった場合 if ( Track.get( track ).getEventCount() >= 1 ) { VsqEvent last_event = Track.get( track ).getEvent( Track.get( track ).getEventCount() - 1 ); Track.get( track ).setEditedEnd( last_event.Clock + last_event.ID.getLength() ); } } #if DEBUG PortUtil.println( " EditedStart,EditedEnd=" + Track.get( track ).getEditedStart() + "," + Track.get( track ).getEditedEnd() ); #endif } updateTotalClocks(); return ret; } } return null; #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_ID_CONTAINTS_RANGE ) { #region EVENT_CHANGE_ID_CONTAINTS_RANGE int track = (Integer)command.Args[0]; int[] internal_ids = (int[])command.Args[1]; VsqID[] values = (VsqID[])command.Args[2]; VsqID[] inv_values = new VsqID[values.Length]; for ( int i = 0; i < internal_ids.Length; i++ ) { for ( Iterator itr = Track.get( track ).getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_ids[i] ) { inv_values[i] = (VsqID)item.ID.clone(); int max_length = Math.Max( item.ID.getLength(), values[i].getLength() ); Track.get( track ).setEditedStart( item.Clock ); Track.get( track ).setEditedEnd( item.Clock + max_length ); item.ID = (VsqID)values[i].clone(); if ( item.ID.type == VsqIDType.Singer ) { // 歌手変更の場合、次に現れる歌手変更の位置まで編集の影響が及ぶ boolean found = false; for ( Iterator itr2 = Track.get( track ).getSingerEventIterator(); itr2.hasNext(); ) { VsqEvent item2 = (VsqEvent)itr2.next(); if ( item.Clock < item2.Clock ) { Track.get( track ).setEditedEnd( item2.Clock ); found = true; break; } } if ( !found ) { // 変更対象が、該当トラック最後の歌手変更イベントだった場合 if ( Track.get( track ).getEventCount() >= 1 ) { VsqEvent last_event = Track.get( track ).getEvent( Track.get( track ).getEventCount() - 1 ); Track.get( track ).setEditedEnd( last_event.Clock + last_event.ID.getLength() ); } } } break; } } } updateTotalClocks(); return VsqCommand.generateCommandEventChangeIDContaintsRange( track, internal_ids, inv_values ); #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_CLOCK_AND_ID_CONTAINTS ) { #region EVENT_CHANGE_CLOCK_AND_ID_CONTAINTS int track = (Integer)command.Args[0]; int internal_id = (Integer)command.Args[1]; int new_clock = (Integer)command.Args[2]; VsqID value = (VsqID)command.Args[3]; VsqTrack target = Track.get( track ); for ( Iterator itr = target.getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_id ) { VsqCommand ret = VsqCommand.generateCommandEventChangeClockAndIDContaints( track, internal_id, item.Clock, item.ID ); int max_length = Math.Max( item.ID.getLength(), value.getLength() ); int min = Math.Min( item.Clock, new_clock ); int max = Math.Max( item.Clock + max_length, new_clock + max_length ); item.ID = (VsqID)value.clone(); item.Clock = new_clock; target.setEditedStart( min ); target.setEditedEnd( max ); target.sortEvent(); updateTotalClocks(); return ret; } } return null; #endregion } else if ( type == VsqCommandType.EVENT_CHANGE_CLOCK_AND_ID_CONTAINTS_RANGE ) { #region EVENT_CHANGE_CLOCK_AND_ID_CONTAINTS_RANGE int track = (Integer)command.Args[0]; int[] internal_ids = (int[])command.Args[1]; int[] clocks = (int[])command.Args[2]; VsqID[] values = (VsqID[])command.Args[3]; Vector inv_id = new Vector(); Vector inv_clock = new Vector(); for ( int i = 0; i < internal_ids.Length; i++ ) { for ( Iterator itr = Track.get( track ).getEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( item.InternalID == internal_ids[i] ) { inv_id.add( (VsqID)item.ID.clone() ); inv_clock.add( item.Clock ); int max_length = Math.Max( item.ID.getLength(), values[i].getLength() ); int min = Math.Min( item.Clock, clocks[i] ); int max = Math.Max( item.Clock + max_length, clocks[i] + max_length ); Track.get( track ).setEditedStart( min ); Track.get( track ).setEditedEnd( max ); item.ID = (VsqID)values[i].clone(); item.Clock = clocks[i]; break; } } } Track.get( track ).sortEvent(); updateTotalClocks(); return VsqCommand.generateCommandEventChangeClockAndIDContaintsRange( track, internal_ids, PortUtil.convertIntArray( inv_clock.toArray( new Integer[] { } ) ), inv_id.toArray( new VsqID[] { } ) ); #if DEBUG PortUtil.println( " TrackChangeClockAndIDContaintsRange" ); PortUtil.println( " track=" + track ); for ( int i = 0; i < internal_ids.Length; i++ ) { PortUtil.println( " id=" + internal_ids[i] + "; clock=" + clocks[i] + "; ID=" + values[i].ToString() ); } #endif #endregion } else if ( type == VsqCommandType.TRACK_CHANGE_NAME ) { #region TRACK_CHANGE_NAME int track = (Integer)command.Args[0]; String new_name = (String)command.Args[1]; VsqCommand ret = VsqCommand.generateCommandTrackChangeName( track, Track.get( track ).getName() ); Track.get( track ).setName( new_name ); return ret; #endregion } else if ( type == VsqCommandType.TRACK_REPLACE ) { #region TRACK_REPLACE int track = (Integer)command.Args[0]; VsqTrack item = (VsqTrack)command.Args[1]; VsqCommand ret = VsqCommand.generateCommandTrackReplace( track, Track.get( track ) ); Track.set( track, item ); updateTotalClocks(); return ret; #endregion } else if ( type == VsqCommandType.TRACK_CHANGE_PLAY_MODE ) { #region TRACK_CHANGE_PLAY_MODE int track = (Integer)command.Args[0]; int play_mode = (Integer)command.Args[1]; VsqCommand ret = VsqCommand.generateCommandTrackChangePlayMode( track, Track.get( track ).getCommon().PlayMode ); Track.get( track ).getCommon().PlayMode = play_mode; return ret; #endregion } else if ( type == VsqCommandType.EVENT_REPLACE ) { #region EVENT_REPLACE int track = (Integer)command.Args[0]; VsqEvent item = (VsqEvent)command.Args[1]; VsqCommand ret = null; for ( int i = 0; i < Track.get( track ).getEventCount(); i++ ) { VsqEvent ve = Track.get( track ).getEvent( i ); if ( ve.InternalID == item.InternalID ) { ret = VsqCommand.generateCommandEventReplace( track, ve ); Track.get( track ).setEvent( i, item ); break; } } Track.get( track ).sortEvent(); updateTotalClocks(); return ret; #endregion } else if ( type == VsqCommandType.EVENT_REPLACE_RANGE ) { #region EVENT_REPLACE_RANGE int track = (Integer)command.Args[0]; VsqEvent[] items = (VsqEvent[])command.Args[1]; VsqCommand ret = null; VsqEvent[] reverse = new VsqEvent[items.Length]; for ( int i = 0; i < items.Length; i++ ) { VsqEvent ve = items[i]; for ( int j = 0; j < Track.get( track ).getEventCount(); j++ ) { VsqEvent ve2 = (VsqEvent)Track.get( track ).getEvent( j ); if ( ve2.InternalID == ve.InternalID ) { reverse[i] = (VsqEvent)ve2.clone(); Track.get( track ).setEvent( j, items[i] ); break; } } } Track.get( track ).sortEvent(); updateTotalClocks(); ret = VsqCommand.generateCommandEventReplaceRange( track, reverse ); return ret; #endregion } return null; } private void processTrackCurveEdit( int track, String curve, Vector delete, TreeMap add, Vector inv_delete, TreeMap inv_add ){ VsqBPList list = Track.get( track ).getCurve( curve ); // 現在の編集範囲を取得 int edited_start = Track.get( track ).getEditedStart(); int edited_end = Track.get( track ).getEditedEnd(); // 逆コマンド発行用 inv_delete.clear(); inv_add.clear(); // 最初に削除コマンドを実行 for ( Iterator itr = delete.iterator(); itr.hasNext(); ) { long id = (Long)itr.next(); VsqBPPairSearchContext item = list.findElement( id ); if ( item.index >= 0 ) { int clock = item.clock; list.removeElementAt( item.index ); inv_add.put( clock, new VsqBPPair( item.point.value, item.point.id ) ); edited_start = Math.Min( edited_start, clock ); edited_end = Math.Max( edited_end, clock ); } } // 追加コマンドを実行 for ( Iterator itr = add.keySet().iterator(); itr.hasNext(); ) { int clock = (Integer)itr.next(); VsqBPPair item = add.get( clock ); list.addWithID( clock, item.value, item.id ); inv_delete.add( item.id ); edited_start = Math.Min( edited_start, clock ); edited_end = Math.Max( edited_end, clock ); } // 編集範囲の更新 Track.get( track ).setEditedStart( edited_start ); Track.get( track ).setEditedEnd( edited_end ); } /// /// VSQファイルの指定されたクロック範囲のイベント等を削除します /// /// 編集対象のVsqFileインスタンス /// 削除を行う範囲の開始クロック /// 削除を行う範囲の終了クロック public void removePart( int clock_start, int clock_end ) { int dclock = clock_end - clock_start; // テンポ情報の削除、シフト boolean changed = true; Vector buf = new Vector( TempoTable ); int tempo_at_clock_start = getTempoAt( clock_start ); int tempo_at_clock_end = getTempoAt( clock_end ); TempoTable.clear(); boolean just_on_clock_end_added = false; for ( int i = 0; i < buf.size(); i++ ) { if ( buf.get( i ).Clock < clock_start ) { TempoTable.add( (TempoTableEntry)buf.get( i ).clone() ); } else if ( clock_end <= buf.get( i ).Clock ) { TempoTableEntry tte = (TempoTableEntry)buf.get( i ).clone(); tte.Clock = tte.Clock - dclock; if ( clock_end == buf.get( i ).Clock ) { TempoTable.add( tte ); just_on_clock_end_added = true; } else { 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 ( 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(); for ( int track = 1; track < Track.size(); track++ ) { // 削除する範囲に歌手変更イベントが存在するかどうかを検査。 VsqEvent t_last_singer = null; for ( Iterator itr = Track.get( track ).getSingerEventIterator(); itr.hasNext(); ) { VsqEvent ve = (VsqEvent)itr.next(); if ( clock_start <= ve.Clock && ve.Clock < clock_end ) { t_last_singer = ve; } if ( ve.Clock == clock_end ) { t_last_singer = null; // 後でclock_endの位置に補うが、そこにに既に歌手変更イベントがあるとまずいので。 } } VsqEvent last_singer = null; if ( t_last_singer != null ) { last_singer = (VsqEvent)t_last_singer.clone(); last_singer.Clock = clock_end; } changed = true; // イベントの削除 while ( changed ) { changed = false; for ( int i = 0; i < Track.get( track ).getEventCount(); i++ ) { if ( clock_start <= Track.get( track ).getEvent( i ).Clock && Track.get( track ).getEvent( i ).Clock < clock_end ) { Track.get( track ).removeEvent( i ); changed = true; break; } } } // クロックのシフト if ( last_singer != null ) { Track.get( track ).addEvent( last_singer ); //歌手変更イベントを補う } for ( int i = 0; i < Track.get( track ).getEventCount(); i++ ) { if ( clock_end <= Track.get( track ).getEvent( i ).Clock ) { Track.get( track ).getEvent( i ).Clock -= dclock; } } for ( int i = 0; i < _CURVES.Length; i++ ) { String curve = _CURVES[i]; if ( curve.Equals( "VEL" ) ) { continue; } VsqBPList buf_bplist = (VsqBPList)Track.get( track ).getCurve( curve ).clone(); Track.get( track ).getCurve( curve ).clear(); int value_at_end = buf_bplist.getValue( clock_end ); boolean at_end_added = false; for ( Iterator itr = buf_bplist.keyClockIterator(); itr.hasNext(); ) { int key = (Integer)itr.next(); if ( key < clock_start ) { Track.get( track ).getCurve( curve ).add( key, buf_bplist.getValue( key ) ); } else if ( clock_end <= key ) { if ( key == clock_end ) { at_end_added = true; } Track.get( track ).getCurve( curve ).add( key - dclock, buf_bplist.getValue( key ) ); } } if ( !at_end_added ) { Track.get( track ).getCurve( curve ).add( clock_end - dclock, value_at_end ); } } } } /// /// vsqファイル全体のイベントを,指定したクロックだけ遅らせます. /// ただし,曲頭のテンポ変更イベントと歌手変更イベントはクロック0から移動しません. /// この操作を行うことで,TimesigTableの情報は破綻します(仕様です). /// /// public static void shift( VsqFile vsq, int delta_clock ) { if ( delta_clock == 0 ) { return; } int dclock = (int)delta_clock; for ( int i = 0; i < vsq.TempoTable.size(); i++ ) { if ( vsq.TempoTable.get( i ).Clock > 0 ) { vsq.TempoTable.get( i ).Clock = vsq.TempoTable.get( i ).Clock + dclock; } } vsq.updateTempoInfo(); for ( int track = 1; track < vsq.Track.size(); track++ ) { for ( int i = 0; i < vsq.Track.get( track ).getEventCount(); i++ ) { if ( vsq.Track.get( track ).getEvent( i ).Clock > 0 ) { vsq.Track.get( track ).getEvent( i ).Clock += dclock; } } for ( int i = 0; i < _CURVES.Length; i++ ) { String curve = _CURVES[i]; if ( curve.Equals( "VEL" ) ) { continue; } // 順番に+=dclockしていくとVsqBPList内部のSortedListの値がかぶる可能性がある. VsqBPList edit = vsq.Track.get( track ).getCurve( curve ); VsqBPList new_one = new VsqBPList( edit.getDefault(), edit.getMinimum(), edit.getMaximum() ); for ( Iterator itr2 = edit.keyClockIterator(); itr2.hasNext(); ) { int key = (Integer)itr2.next(); new_one.add( key + dclock, edit.getValue( key ) ); } vsq.Track.get( track ).setCurve( curve, new_one ); } } vsq.updateTotalClocks(); } /// /// このインスタンスのコピーを作成します /// /// このインスタンスのコピー public Object clone() { VsqFile ret = new VsqFile(); ret.Track = new Vector(); for ( int i = 0; i < Track.size(); i++ ) { ret.Track.add( (VsqTrack)Track.get( i ).clone() ); } ret.TempoTable = new Vector(); for ( int i = 0; i < TempoTable.size(); i++ ) { ret.TempoTable.add( (TempoTableEntry)TempoTable.get( i ).clone() ); } ret.TimesigTable = new Vector(); for ( int i = 0; i < TimesigTable.size(); i++ ) { ret.TimesigTable.add( (TimeSigTableEntry)TimesigTable.get( i ).clone() ); } ret.m_tpq = m_tpq; ret.TotalClocks = TotalClocks; ret.m_base_tempo = m_base_tempo; ret.Master = (VsqMaster)Master.clone(); ret.Mixer = (VsqMixer)Mixer.clone(); //ret.m_premeasure_clocks = m_premeasure_clocks; return ret; } #if !JAVA public object Clone() { return clone(); } #endif private VsqFile() { } #if JAVA private class BarLineIterator implements Iterator{ #else private class BarLineIterator : Iterator { #endif private Vector m_list; private int m_end_clock; private int i; private int clock; int local_denominator; int local_numerator; int clock_step; int t_end; int local_clock; int bar_counter; public BarLineIterator( Vector list, int end_clock ) { m_list = list; m_end_clock = end_clock; i = 0; t_end = -1; clock = 0; } public Object next() { int mod = clock_step * local_numerator; if ( clock < t_end ) { if ( (clock - local_clock) % mod == 0 ) { bar_counter++; VsqBarLineType ret = new VsqBarLineType( clock, true, local_denominator, local_numerator, bar_counter ); clock += clock_step; return ret; } else { VsqBarLineType ret = new VsqBarLineType( clock, false, local_denominator, local_numerator, bar_counter ); clock += clock_step; return ret; } } if ( i < m_list.size() ) { local_denominator = m_list.get( i ).Denominator; local_numerator = m_list.get( i ).Numerator; local_clock = m_list.get( i ).Clock; int local_bar_count = m_list.get( i ).BarCount; clock_step = 480 * 4 / local_denominator; mod = clock_step * local_numerator; bar_counter = local_bar_count - 1; t_end = m_end_clock; if ( i + 1 < m_list.size() ) { t_end = m_list.get( i + 1 ).Clock; } i++; clock = local_clock; if ( clock < t_end ) { if ( (clock - local_clock) % mod == 0 ) { bar_counter++; VsqBarLineType ret = new VsqBarLineType( clock, true, local_denominator, local_numerator, bar_counter ); clock += clock_step; return ret; } else { VsqBarLineType ret = new VsqBarLineType( clock, false, local_denominator, local_numerator, bar_counter ); clock += clock_step; return ret; } } } return null; } public void remove() { //throw new Exception( "com.boare.vsq.VsqFile.BarLineIterator#remove; not implemented" ); } public boolean hasNext() { if ( clock < m_end_clock ) { return true; } else { return false; } } } /// /// 小節の区切りを順次返すIterator。 /// /// public Iterator getBarLineIterator( int end_clock ) { return new BarLineIterator( TimesigTable, end_clock ); } /// /// 基本テンポ値を取得します /// public int getBaseTempo() { return m_base_tempo; } /// /// プリメジャー値を取得します /// public int getPreMeasure() { return Master.PreMeasure; } /// /// プリメジャー部分の長さをクロックに変換した値を取得します. /// public int getPreMeasureClocks() { return calculatePreMeasureInClock(); } /// /// プリメジャーの長さ(クロック)を計算します。 /// private int calculatePreMeasureInClock() { int pre_measure = Master.PreMeasure; int last_bar_count = TimesigTable.get( 0 ).BarCount; int last_clock = TimesigTable.get( 0 ).Clock; int last_denominator = TimesigTable.get( 0 ).Denominator; int last_numerator = TimesigTable.get( 0 ).Numerator; for ( int i = 1; i < TimesigTable.size(); i++ ) { if ( TimesigTable.get( i ).BarCount >= pre_measure ) { break; } else { last_bar_count = TimesigTable.get( i ).BarCount; last_clock = TimesigTable.get( i ).Clock; last_denominator = TimesigTable.get( i ).Denominator; last_numerator = TimesigTable.get( i ).Numerator; } } int remained = pre_measure - last_bar_count;//プリメジャーの終わりまでの残り小節数 return last_clock + remained * last_numerator * 480 * 4 / last_denominator; } /// /// 指定したクロックにおける、clock=0からの演奏経過時間(sec)を取得します /// /// /// public double getSecFromClock( double clock ) { int c = TempoTable.size(); for ( int i = c - 1; i >= 0; i-- ) { TempoTableEntry item = TempoTable.get( 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; } } double sec_per_clock = m_base_tempo * 1e-6 / 480.0; return clock * sec_per_clock; } /// /// 指定した時刻における、クロックを取得します /// /// /// public double getClockFromSec( double time ) { // timeにおけるテンポを取得 int tempo = m_base_tempo; double base_clock = 0; double base_time = 0f; int c = TempoTable.size(); if ( c == 0 ) { tempo = m_base_tempo; base_clock = 0; base_time = 0f; } else if ( c == 1 ) { tempo = TempoTable.get( 0 ).Tempo; base_clock = TempoTable.get( 0 ).Clock; base_time = TempoTable.get( 0 ).Time; } else { for ( int i = c - 1; i >= 0; i-- ) { TempoTableEntry item = TempoTable.get( i ); if ( item.Time < time ) { return item.Clock + (time - item.Time) * m_tpq * 1000000.0 / item.Tempo; } } } double dt = time - base_time; return base_clock + dt * m_tpq * 1000000.0 / (double)tempo; } /// /// 指定したクロックにおける拍子を取得します /// /// /// /// public Timesig getTimesigAt( int clock ) { Timesig ret = new Timesig(); ret.numerator = 4; ret.denominator = 4; int index = 0; int c = TimesigTable.size(); for ( int i = c - 1; i >= 0; i-- ) { index = i; if ( TimesigTable.get( i ).Clock <= clock ) { break; } } ret.numerator = TimesigTable.get( index ).Numerator; ret.denominator = TimesigTable.get( index ).Denominator; return ret; } public Timesig getTimesigAt( int clock, ByRef bar_count ) { int index = 0; int c = TimesigTable.size(); for ( int i = c - 1; i >= 0; i-- ) { index = i; if ( TimesigTable.get( i ).Clock <= clock ) { break; } } TimeSigTableEntry item = TimesigTable.get( index ); Timesig ret = new Timesig(); ret.numerator = item.Numerator; ret.denominator = item.Denominator; int diff = clock - item.Clock; int clock_per_bar = 480 * 4 / ret.denominator * ret.numerator; bar_count.value = item.BarCount + diff / clock_per_bar; return ret; } /// /// 指定したクロックにおけるテンポを取得します。 /// /// /// public int getTempoAt( int clock ) { int index = 0; int c = TempoTable.size(); for ( int i = c - 1; i >= 0; i-- ) { index = i; if ( TempoTable.get( i ).Clock <= clock ) { break; } } return TempoTable.get( index ).Tempo; } /// /// 指定した小節の開始クロックを調べます。ここで使用する小節数は、プリメジャーを考慮しない。即ち、曲頭の小節が0である。 /// /// /// public int getClockFromBarCount( int bar_count ) { int index = 0; int c = TimesigTable.size(); for ( int i = c - 1; i >= 0; i-- ) { index = i; if ( TimesigTable.get( i ).BarCount <= bar_count ) { break; } } TimeSigTableEntry item = TimesigTable.get( 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; } /// /// 指定したクロックが、曲頭から何小節目に属しているかを調べます。ここで使用する小節数は、プリメジャーを考慮しない。即ち、曲頭の小節が0である。 /// /// /// public int getBarCountFromClock( int clock ) { int index = 0; int c = TimesigTable.size(); for ( int i = c - 1; i >= 0; i-- ) { index = i; if ( TimesigTable.get( i ).Clock <= clock ) { break; } } int bar_count = 0; if ( index >= 0 ) { int last_clock = TimesigTable.get( index ).Clock; int t_bar_count = TimesigTable.get( index ).BarCount; int numerator = TimesigTable.get( index ).Numerator; int denominator = TimesigTable.get( index ).Denominator; int clock_per_bar = numerator * 480 * 4 / denominator; bar_count = t_bar_count + (clock - last_clock) / clock_per_bar; } return bar_count; } /// /// 4分の1拍子1音あたりのクロック数を取得します /// public int getTickPerQuarter() { return m_tpq; } /// /// 空のvsqファイルを構築します /// /// /// /// /// public VsqFile( String singer, int pre_measure, int numerator, int denominator, int tempo ) { TotalClocks = pre_measure * 480 * 4 / denominator * numerator; m_tpq = 480; Track = new Vector(); Track.add( new VsqTrack( tempo, numerator, denominator ) ); Track.add( new VsqTrack( "Voice1", singer ) ); Master = new VsqMaster( pre_measure ); #if DEBUG PortUtil.println( "VsqFile.ctor()" ); #endif Mixer = new VsqMixer( 0, 0, 0, 0 ); Mixer.Slave.add( new VsqMixerEntry( 0, 0, 0, 0 ) ); TimesigTable = new Vector(); TimesigTable.add( new TimeSigTableEntry( 0, numerator, denominator, 0 ) ); TempoTable = new Vector(); TempoTable.add( new TempoTableEntry( 0, tempo, 0.0 ) ); m_base_tempo = tempo; //m_premeasure_clocks = calculatePreMeasureInClock(); } /// /// vsqファイルからのコンストラクタ /// /// public VsqFile( String _fpath, String encoding ) #if JAVA throws FileNotFoundException #endif { TempoTable = new Vector(); TimesigTable = new Vector(); m_tpq = 480; // SMFをコンバートしたテキストファイルを作成 MidiFile mf = new MidiFile( _fpath ); Track = new Vector(); int num_track = mf.getTrackCount(); #if DEBUG PortUtil.println( "VsqFile#.ctor; num_track=" + num_track ); #endif for ( int i = 0; i < num_track; i++ ) { Track.add( new VsqTrack( mf.getMidiEventList( i ), encoding ) ); } Master = (VsqMaster)Track.get( 1 ).getMaster().clone(); Mixer = (VsqMixer)Track.get( 1 ).getMixer().clone(); Track.get( 1 ).setMaster( null ); Track.get( 1 ).setMixer( null ); #if DEBUG System.Diagnostics.Debug.WriteLine( "VsqFile.ctor()" ); #endif int master_track = -1; for ( int i = 0; i < Track.size(); i++ ) { #if DEBUG System.Diagnostics.Debug.WriteLine( " m_tracks[i].Name=" + Track.get( i ).getName() ); #endif if ( Track.get( i ).getName().Equals( "Master Track" ) ) { master_track = i; break; } } int prev_tempo; int prev_index; double prev_time; if ( master_track >= 0 ) { #region TempoListの作成 // MIDI event リストの取得 Vector midi_event = mf.getMidiEventList( master_track );//.TempoTable; // とりあえずtempo_tableに格納 m_base_tempo = 500000; prev_tempo = 500000; prev_index = 0; double thistime; prev_time = 0.0; int count = -1; int midi_event_size = midi_event.size(); for ( int j = 0; j < midi_event_size; j++ ) { MidiEvent itemj = midi_event.get( j ); if ( itemj.firstByte == (byte)0xff && itemj.data.Length >= 4 && itemj.data[0] == (byte)0x51 ) { count++; if ( count == 0 && itemj.clock != 0 ) { TempoTable.add( new TempoTableEntry( 0, 500000, 0.0 ) ); m_base_tempo = 500000; prev_tempo = 500000; } int current_tempo = itemj.data[1] << 16 | itemj.data[2] << 8 | itemj.data[3]; int current_index = (int)midi_event.get( 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; prev_index = current_index; prev_time = thistime; } } Collections.sort( TempoTable ); #endregion #region TimeSigTableの作成 //Vector time_sigs = mf.getMidiEventList( master_track );//].TimesigTable; int dnomi = 4;// time_sigs[0].Data[1]; int numer = 4; /*for ( int i = 0; i < time_sigs[0].Data[2]; i++ ) { numer = numer * 2; }*/ //m_timesig_table.Add( new TimeSigTableEntry( 0, numer, dnomi, 0 ) ); count = -1; for ( int j = 0; j < midi_event.size(); j++ ) { if ( midi_event.get( j ).firstByte == (byte)0xff && midi_event.get( j ).data.Length >= 5 && midi_event.get( j ).data[0] == (byte)0x58 ) { count++; numer = midi_event.get( j ).data[1]; dnomi = 1; for ( int i = 0; i < midi_event.get( j ).data[2]; i++ ) { dnomi = dnomi * 2; } if ( count == 0 ) { int numerator = 4; int denominator = 4; int clock = 0; int bar_count = 0; if ( midi_event.get( 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.get( j ).clock / (480 * 4) ) ); count++; } } else { int numerator = TimesigTable.get( count - 1 ).Numerator; int denominator = TimesigTable.get( count - 1 ).Denominator; int clock = TimesigTable.get( count - 1 ).Clock; int bar_count = TimesigTable.get( count - 1 ).BarCount; int dif = 480 * 4 / denominator * numerator;//1小節が何クロックか? bar_count += ((int)midi_event.get( j ).clock - clock) / dif; TimesigTable.add( new TimeSigTableEntry( (int)midi_event.get( j ).clock, numer, dnomi, bar_count ) ); } } } #endregion } // 曲の長さを計算 updateTempoInfo(); updateTimesigInfo(); //m_premeasure_clocks = calculatePreMeasureInClock(); updateTotalClocks(); #if DEBUG System.Diagnostics.Debug.WriteLine( " m_total_clocks=" + TotalClocks ); #endif } /// /// TimeSigTableの[*].Clockの部分を更新します /// public void updateTimesigInfo() { #if DEBUG PortUtil.println( "VsqFile.UpdateTimesigInfo()" ); #endif if ( TimesigTable.get( 0 ).Clock != 0 ) { return; } TimesigTable.get( 0 ).Clock = 0; Collections.sort( TimesigTable ); int count = TimesigTable.size(); for ( int j = 1; j < count; j++ ) { TimeSigTableEntry item = TimesigTable.get( j - 1 ); int numerator = item.Numerator; int denominator = item.Denominator; int clock = item.Clock; int bar_count = item.BarCount; int dif = 480 * 4 / denominator * numerator;//1小節が何クロックか? clock += (TimesigTable.get( j ).BarCount - bar_count) * dif; TimesigTable.get( j ).Clock = clock; } #if DEBUG PortUtil.println( "TimesigTable;" ); for ( int i = 0; i < TimesigTable.size(); i++ ) { PortUtil.println( " " + TimesigTable.get( i ).Clock + " " + TimesigTable.get( i ).Numerator + "/" + TimesigTable.get( i ).Denominator ); } #endif } /// /// TempoTableの[*].Timeの部分を更新します /// public void updateTempoInfo() { if ( TempoTable.size() == 0 ) { TempoTable.add( new TempoTableEntry( 0, getBaseTempo(), 0.0 ) ); } Collections.sort( TempoTable ); if ( TempoTable.get( 0 ).Clock != 0 ) { TempoTable.get( 0 ).Time = (double)getBaseTempo() * (double)TempoTable.get( 0 ).Clock / (getTickPerQuarter() * 1000000.0); } else { TempoTable.get( 0 ).Time = 0.0; } double prev_time = TempoTable.get( 0 ).Time; int prev_clock = TempoTable.get( 0 ).Clock; int prev_tempo = TempoTable.get( 0 ).Tempo; double inv_tpq_sec = 1.0 / (getTickPerQuarter() * 1000000.0); for ( int i = 1; i < TempoTable.size(); i++ ) { TempoTable.get( i ).Time = prev_time + (double)prev_tempo * (double)(TempoTable.get( i ).Clock - prev_clock) * inv_tpq_sec; prev_time = TempoTable.get( i ).Time; prev_tempo = TempoTable.get( i ).Tempo; prev_clock = TempoTable.get( i ).Clock; } } /// /// VsqFile.Executeの実行直後などに、m_total_clocksの値を更新する /// public void updateTotalClocks() { int max = getPreMeasureClocks(); for ( int i = 1; i < Track.size(); i++ ) { VsqTrack track = Track.get( i ); for ( Iterator itr = track.getEventIterator(); itr.hasNext(); ) { VsqEvent ve = (VsqEvent)itr.next(); max = Math.Max( max, ve.Clock + ve.ID.getLength() ); } for ( int j = 0; j < _CURVES.Length; j++ ) { String vct = _CURVES[j]; if ( vct.Equals( "VEL" ) ) { continue; } VsqBPList list = track.getCurve( vct ); if ( list != null && list.size() > 0 ) { int keys = list.size(); int last_key = list.getKeyClock( keys - 1 ); max = Math.Max( max, last_key ); } } } TotalClocks = max; } /// /// 曲の長さを取得する。(sec) /// public double getTotalSec() { return getSecFromClock( (int)TotalClocks ); } /// /// 指定された番号のトラックに含まれる歌詞を指定されたファイルに出力します /// /// /// public void printLyricTable( int track, String fpath ) { BufferedWriter sw = null; try { sw = new BufferedWriter( new FileWriter( fpath ) ); for ( int i = 0; i < Track.get( track ).getEventCount(); i++ ) { int Length; // timesignal int time_signal = Track.get( track ).getEvent( i ).Clock; // イベントで指定されたIDがLyricであった場合 if ( Track.get( track ).getEvent( i ).ID.type == VsqIDType.Anote ) { // 発音長を取得 Length = Track.get( track ).getEvent( i ).ID.getLength(); // tempo_tableから、発音開始時のtempoを取得 int last = TempoTable.size() - 1; int tempo = TempoTable.get( last ).Tempo; int prev_index = TempoTable.get( last ).Clock; double prev_time = TempoTable.get( last ).Time; for ( int j = 1; j < TempoTable.size(); j++ ) { if ( TempoTable.get( j ).Clock > time_signal ) { tempo = TempoTable.get( j - 1 ).Tempo; prev_index = TempoTable.get( j - 1 ).Clock; prev_time = TempoTable.get( j - 1 ).Time; break; } } int current_index = Track.get( track ).getEvent( i ).Clock; double start_time = prev_time + (double)(current_index - prev_index) * (double)tempo / (m_tpq * 1000000.0); // TODO: 単純に + Lengthしただけではまずいはず。要検討 double end_time = start_time + ((double)Length) * ((double)tempo) / (m_tpq * 1000000.0); sw.write( Track.get( track ).getEvent( i ).Clock + "," + PortUtil.formatDecimal( "0.000000", start_time ) + "," + PortUtil.formatDecimal( "0.000000", end_time ) + "," + Track.get( track ).getEvent( i ).ID.LyricHandle.L0.Phrase + "," + Track.get( track ).getEvent( i ).ID.LyricHandle.L0.getPhoneticSymbol() ); sw.newLine(); } } } catch ( Exception ex ) { } finally { if ( sw != null ) { try { sw.close(); } catch ( Exception ex2 ) { } } } } public Vector generateMetaTextEvent( int track, String encoding ) { String _NL = "" + (char)(byte)0x0a; Vector ret = new Vector(); TextMemoryStream sr = null; try { sr = new TextMemoryStream(); Track.get( track ).printMetaText( sr, TotalClocks + 120, calculatePreMeasureInClock() ); sr.rewind(); int line_count = -1; String tmp = ""; if ( sr.peek() >= 0 ) { #if NEW_IMPL Vector buffer = new Vector(); boolean first = true; while ( sr.peek() >= 0 ) { if ( first ) { tmp = sr.readLine(); first = false; } else { tmp = _NL + sr.readLine(); } Byte[] linebytes = PortUtil.convertByteArray( PortUtil.getEncodedByte( encoding, tmp ) ); buffer.addAll( Arrays.asList( linebytes ) ); while ( getLinePrefixBytes( line_count + 1 ).Length + buffer.size() >= 127 ) { line_count++; byte[] prefix = getLinePrefixBytes( line_count ); MidiEvent add = new MidiEvent(); add.clock = 0; add.firstByte = (byte)0xff; add.data = new byte[128]; add.data[0] = (byte)0x01; int remain = 127; for ( int i = 0; i < prefix.Length; i++ ) { add.data[i + 1] = prefix[i]; } for ( int i = prefix.Length; i < remain; i++ ) { byte d = buffer.get( 0 ); add.data[i + 1] = d; buffer.removeElementAt( 0 ); } ret.add( add ); } } if ( buffer.size() > 0 ) { while ( getLinePrefixBytes( line_count + 1 ).Length + buffer.size() >= 127 ) { line_count++; byte[] prefix = getLinePrefixBytes( line_count ); MidiEvent add = new MidiEvent(); add.clock = 0; add.firstByte = (byte)0xff; add.data = new byte[128]; add.data[0] = (byte)0x01; int remain = 127; for ( int i = 0; i < prefix.Length; i++ ) { add.data[i + 1] = prefix[i]; } for ( int i = prefix.Length; i < remain; i++ ) { add.data[i + 1] = buffer.get( 0 ); buffer.removeElementAt( 0 ); } ret.add( add ); } if ( buffer.size() > 0 ) { line_count++; byte[] prefix = getLinePrefixBytes( line_count ); MidiEvent add = new MidiEvent(); add.clock = 0; add.firstByte = (byte)0xff; int remain = prefix.Length + buffer.size(); add.data = new byte[remain + 1]; add.data[0] = (byte)0x01; for ( int i = 0; i < prefix.Length; i++ ) { add.data[i + 1] = prefix[i]; } for ( int i = prefix.Length; i < remain; i++ ) { add.data[i + 1] = buffer.get( 0 ); buffer.removeElementAt( 0 ); } ret.add( add ); } } #else tmp = sr.readLine(); byte[] line_bytes; while ( sr.peek() >= 0 ) { tmp += _NL + sr.readLine(); while ( PortUtil.getEncodedByteCount( encoding, tmp + getLinePrefix( line_count + 1 ) ) >= 127 ) { line_count++; tmp = getLinePrefix( line_count ) + tmp; String work = substring127Bytes( tmp, encoding );// tmp.Substring( 0, 127 ); tmp = tmp.Substring( PortUtil.getStringLength( work ) ); line_bytes = PortUtil.getEecodedByte( encoding, work ); MidiEvent add = new MidiEvent(); add.clock = 0; add.firstByte = (byte)0xff; //ステータス メタ* add.data = new byte[line_bytes.Length + 1]; add.data[0] = (byte)0x01; //メタテキスト for ( int i = 0; i < line_bytes.Length; i++ ) { add.data[i + 1] = line_bytes[i]; } ret.add( add ); } } // 残りを出力 line_count++; tmp = getLinePrefix( line_count ) + tmp + _NL; while ( PortUtil.getEncodedByteCount( encoding, tmp ) > 127 ) { String work = substring127Bytes( tmp, encoding ); tmp = tmp.Substring( PortUtil.getStringLength( work ) ); line_bytes = PortUtil.getEecodedByte( encoding, work ); MidiEvent add = new MidiEvent(); add.clock = 0; add.firstByte = (byte)0xff; add.data = new byte[line_bytes.Length + 1]; add.data[0] = (byte)0x01; for ( int i = 0; i < line_bytes.Length; i++ ) { add.data[i + 1] = line_bytes[i]; } ret.add( add ); line_count++; tmp = getLinePrefix( line_count ); } line_bytes = PortUtil.getEecodedByte( encoding, tmp ); MidiEvent add0 = new MidiEvent(); add0.firstByte = (byte)0xff; add0.data = new byte[line_bytes.Length + 1]; add0.data[0] = (byte)0x01; for ( int i = 0; i < line_bytes.Length; i++ ) { add0.data[i + 1] = line_bytes[i]; } ret.add( add0 ); #endif } } catch ( Exception ex ) { } finally { if ( sr != null ) { try { sr.close(); } catch ( Exception ex2 ) { } } } #if DEBUG Console.WriteLine( "VsqFile#generateMetaTextEvent; ret.size()=" + ret.size() ); #endif return ret; } /// /// 文字列sの先頭から文字列を切り取るとき,切り取った文字列をencodingによりエンコードした結果が127Byte以下になるように切り取ります. /// /// /// /// private static String substring127Bytes( String s, String encoding ) { int count = Math.Min( 127, PortUtil.getStringLength( s ) ); int c = PortUtil.getEncodedByteCount( encoding, s.Substring( 0, count ) ); if ( c == 127 ) { return s.Substring( 0, count ); } int delta = c > 127 ? -1 : 1; while ( (delta == -1 && c > 127) || (delta == 1 && c < 127) ) { count += delta; if ( delta == -1 && count == 0 ) { break; } else if ( delta == 1 && count == PortUtil.getStringLength( s ) ) { break; } c = PortUtil.getEncodedByteCount( encoding, s.Substring( 0, count ) ); } return s.Substring( 0, count ); } private static void printTrack( VsqFile vsq, int track, RandomAccessFile fs, int msPreSend, String encoding ) #if JAVA throws IOException #endif { #if DEBUG PortUtil.println( "PrintTrack" ); #endif //VsqTrack item = Tracks[track]; String _NL = "" + (char)(byte)0x0a; //ヘッダ fs.write( _MTRK, 0, 4 ); //データ長。とりあえず0 fs.write( new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, 0, 4 ); long first_position = fs.getFilePointer(); //トラック名 writeFlexibleLengthUnsignedLong( fs, (byte)0x00 );//デルタタイム fs.write( (byte)0xff );//ステータスタイプ fs.write( (byte)0x03 );//イベントタイプSequence/Track Name byte[] seq_name = PortUtil.getEncodedByte( encoding, vsq.Track.get( track ).getName() ); writeFlexibleLengthUnsignedLong( fs, (long)seq_name.Length );//seq_nameの文字数 fs.write( seq_name, 0, seq_name.Length ); //Meta Textを準備 Vector meta = vsq.generateMetaTextEvent( track, encoding ); long lastclock = 0; for ( int i = 0; i < meta.size(); i++ ) { writeFlexibleLengthUnsignedLong( fs, (long)(meta.get( i ).clock - lastclock) ); meta.get( i ).writeData( fs ); lastclock = meta.get( i ).clock; } int last = 0; VsqNrpn[] data = generateNRPN( vsq, track, msPreSend ); NrpnData[] nrpns = VsqNrpn.convert( data ); for ( int i = 0; i < nrpns.Length; i++ ) { writeFlexibleLengthUnsignedLong( fs, (long)(nrpns[i].getClock() - last) ); fs.write( (byte)0xb0 ); fs.write( nrpns[i].getParameter() ); fs.write( nrpns[i].Value ); last = nrpns[i].getClock(); } //トラックエンド VsqEvent last_event = vsq.Track.get( track ).getEvent( vsq.Track.get( track ).getEventCount() - 1 ); int last_clock = last_event.Clock + last_event.ID.getLength(); writeFlexibleLengthUnsignedLong( fs, (long)last_clock ); fs.write( (byte)0xff ); fs.write( (byte)0x2f ); fs.write( (byte)0x00 ); long pos = fs.getFilePointer(); fs.seek( first_position - 4 ); writeUnsignedInt( fs, (long)(pos - first_position) ); fs.seek( pos ); } /// /// 指定したクロックにおけるプリセンド・クロックを取得します /// /// /// /// public int getPresendClockAt( int clock, int msPreSend ) { double clock_msec = getSecFromClock( clock ) * 1000.0; float draft_clock_sec = (float)(clock_msec - msPreSend) / 1000.0f; int draft_clock = (int)Math.Floor( getClockFromSec( draft_clock_sec ) ); return clock - draft_clock; } /// /// 指定したトラックから、Expression(DYN)のNRPNリストを作成します /// /// /// /// public static VsqNrpn[] generateExpressionNRPN( VsqFile vsq, int track, int msPreSend ) { Vector ret = new Vector(); VsqBPList dyn = vsq.Track.get( track ).getCurve( "DYN" ); int count = dyn.size(); for ( int i = 0; i < count; i++ ) { int clock = dyn.getKeyClock( i ); int c = clock - vsq.getPresendClockAt( clock, msPreSend ); if ( c >= 0 ) { VsqNrpn add = new VsqNrpn( c, NRPN.CC_E_EXPRESSION, (byte)dyn.getElement( i ) ); ret.add( add ); } } return ret.toArray( new VsqNrpn[] { } ); } public static VsqNrpn[] generateFx2DepthNRPN( VsqFile vsq, int track, int msPreSend ) { Vector ret = new Vector(); VsqBPList fx2depth = vsq.Track.get( track ).getCurve( "fx2depth" ); int count = fx2depth.size(); for ( int i = 0; i < count; i++ ) { int clock = fx2depth.getKeyClock( i ); int c = clock - vsq.getPresendClockAt( clock, msPreSend ); if ( c >= 0 ) { VsqNrpn add = new VsqNrpn( c, NRPN.CC_FX2_EFFECT2_DEPTH, (byte)fx2depth.getElement( i ) ); ret.add( add ); } } return ret.toArray( new VsqNrpn[] { } ); } /// /// 先頭に記録されるNRPNを作成します /// /// public static VsqNrpn generateHeaderNRPN() { VsqNrpn ret = new VsqNrpn( 0, NRPN.CC_BS_VERSION_AND_DEVICE, (byte)0x00, (byte)0x00 ); ret.append( NRPN.CC_BS_DELAY, (byte)0x00, (byte)0x00 ); ret.append( NRPN.CC_BS_LANGUAGE_TYPE, (byte)0x00 ); return ret; } /// /// 歌手変更イベントから,NRPNを作成します /// /// /// /// /// public static VsqNrpn[] generateSingerNRPN( VsqFile vsq, VsqEvent ve, int msPreSend ) { int clock = ve.Clock; double clock_msec = vsq.getSecFromClock( clock ) * 1000.0; int ttempo = vsq.getTempoAt( clock ); double tempo = 6e7 / ttempo; //double sStart = SecFromClock( ve.Clock ); double msEnd = vsq.getSecFromClock( ve.Clock + ve.ID.getLength() ) * 1000.0; int duration = (int)Math.Ceiling( msEnd - clock_msec ); #if DEBUG PortUtil.println( "GenerateNoteNRPN" ); PortUtil.println( " duration=" + duration ); #endif ValuePair d = getMsbAndLsb( duration ); byte duration0 = d.getKey(); byte duration1 = d.getValue(); ValuePair d2 = getMsbAndLsb( msPreSend ); byte delay0 = d2.getKey(); byte delay1 = d2.getValue(); Vector ret = new Vector(); int i = clock - vsq.getPresendClockAt( clock, msPreSend ); VsqNrpn add = new VsqNrpn( i, NRPN.CC_BS_VERSION_AND_DEVICE, (byte)0x00, (byte)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 }; } /// /// 音符イベントから,NRPNを作成します /// /// /// /// /// public static VsqNrpn generateNoteNRPN( VsqFile vsq, int track, VsqEvent ve, int msPreSend, byte note_loc, boolean add_delay_sign ) { int clock = ve.Clock; String renderer = vsq.Track.get( track ).getCommon().Version; double clock_msec = vsq.getSecFromClock( clock ) * 1000.0; int ttempo = vsq.getTempoAt( clock ); double tempo = 6e7 / ttempo; double msEnd = vsq.getSecFromClock( ve.Clock + ve.ID.getLength() ) * 1000.0; int duration = (int)(msEnd - clock_msec); ValuePair dur = getMsbAndLsb( duration ); byte duration0 = dur.getKey(); byte duration1 = dur.getValue(); VsqNrpn add; if ( add_delay_sign ) { ValuePair msp = getMsbAndLsb( msPreSend ); byte delay0 = msp.getKey(); byte delay1 = msp.getValue(); add = new VsqNrpn( clock - vsq.getPresendClockAt( clock, msPreSend ), NRPN.CVM_NM_VERSION_AND_DEVICE, (byte)0x00, (byte)0x00 ); 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, 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, (byte)0x00, (byte)0x00, true ); String icon_id = ve.ID.VibratoHandle.IconID; String num = icon_id.Substring( PortUtil.getStringLength( icon_id ) - 4 ); int vibrato_type = (int)PortUtil.fromHexString( num ); int note_length = ve.ID.getLength(); int vibrato_delay = ve.ID.VibratoDelay; byte bVibratoDuration = (byte)((float)(note_length - vibrato_delay) / (float)note_length * 127); byte bVibratoDelay = (byte)((byte)0x7f - bVibratoDuration); 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(); String s = ""; for ( int j = 0; j < spl.Length; j++ ) { s += spl[j]; } char[] symbols = s.ToCharArray(); if ( renderer.StartsWith( "DSB2" ) ) { add.append( 0x5011, (byte)0x01, true );//TODO: (byte)0x5011の意味は解析中 } add.append( NRPN.CVM_NM_PHONETIC_SYMBOL_BYTES, (byte)symbols.Length, true );// (byte)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( (0x50 << 8) | (0x13 + count), (byte)chars[k], (byte)ve.ID.LyricHandle.L0.getConsonantAdjustment()[j], true ); // Phonetic symbol j } else { add.append( (0x50 << 8) | (0x13 + count), (byte)chars[k], true ); // Phonetic symbol j } } } if ( !renderer.StartsWith( "DSB2" ) ) { add.append( NRPN.CVM_NM_PHONETIC_SYMBOL_CONTINUATION, (byte)0x7f, true ); // End of phonetic symbols } if ( renderer.StartsWith( "DSB3" ) ) { int v1mean = ve.ID.PMBendDepth * 60 / 100; if ( v1mean < 0 ) { v1mean = 0; } if ( 60 < v1mean ) { v1mean = 60; } 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, true );// (byte)0x50(v1mean) add.append( NRPN.CVM_NM_D1MEAN, (byte)d1mean, true );// (byte)0x51(d1mean) add.append( NRPN.CVM_NM_D1MEAN_FIRST_NOTE, (byte)0x14, true );// (byte)0x52(d1meanFirstNote) add.append( NRPN.CVM_NM_D2MEAN, (byte)d2mean, true );// (byte)0x53(d2mean) add.append( NRPN.CVM_NM_D4MEAN, (byte)ve.ID.d4mean, true );// (byte)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 ); // (byte)0x56(vMeanNoteTransition) add.append( NRPN.CVM_NM_PMEAN_ENDING_NOTE, (byte)ve.ID.pMeanEndingNote, true );// (byte)0x57(pMeanEndingNote) add.append( NRPN.CVM_NM_ADD_PORTAMENTO, (byte)ve.ID.PMbPortamentoUse, true );// (byte)0x58(AddScoopToUpInternals&AddPortamentoToDownIntervals) byte decay = (byte)(ve.ID.DEMdecGainRate / 100.0 * (byte)0x64); add.append( NRPN.CVM_NM_CHANGE_AFTER_PEAK, decay, true );// (byte)0x59(changeAfterPeak) byte accent = (byte)((byte)0x64 * ve.ID.DEMaccent / 100.0); add.append( NRPN.CVM_NM_ACCENT, accent, true );// (byte)0x5a(Accent) } if ( renderer.StartsWith( "UTU0" ) ) { // エンベロープ if ( ve.UstEvent != null ) { UstEnvelope env = null; if ( ve.UstEvent.Envelope != null ) { env = ve.UstEvent.Envelope; } else { env = new UstEnvelope(); } int[] vals = null; vals = new int[10]; vals[0] = env.p1; vals[1] = env.p2; vals[2] = env.p3; vals[3] = env.v1; vals[4] = env.v2; vals[5] = env.v3; vals[6] = env.v4; vals[7] = env.p4; vals[8] = env.p5; vals[9] = env.v5; for ( int i = 0; i < vals.Length; i++ ) { //(value3.msb & (byte)0xf) << 28 | (value2.msb & (byte)0x7f) << 21 | (value2.lsb & (byte)0x7f) << 14 | (value1.msb & (byte)0x7f) << 7 | (value1.lsb & (byte)0x7f) byte msb, lsb; int v = vals[i]; lsb = (byte)(v & (byte)0x7f); v = v >> 7; msb = (byte)(v & (byte)0x7f); v = v >> 7; add.append( NRPN.CVM_EXNM_ENV_DATA1, msb, lsb ); lsb = (byte)(v & (byte)0x7f); v = v >> 7; msb = (byte)(v & (byte)0x7f); v = v >> 7; add.append( NRPN.CVM_EXNM_ENV_DATA2, msb, lsb ); msb = (byte)(v & (byte)0xf); add.append( NRPN.CVM_EXNM_ENV_DATA3, msb ); add.append( NRPN.CVM_EXNM_ENV_DATA_CONTINUATION, (byte)0x00 ); } add.append( NRPN.CVM_EXNM_ENV_DATA_CONTINUATION, (byte)0x7f ); // モジュレーション ValuePair m; if ( -100 <= ve.UstEvent.Moduration && ve.UstEvent.Moduration <= 100 ) { m = getMsbAndLsb( ve.UstEvent.Moduration + 100 ); add.append( NRPN.CVM_EXNM_MODURATION, m.getKey(), m.getValue() ); } // 先行発声 if ( ve.UstEvent.PreUtterance != 0 ) { m = getMsbAndLsb( ve.UstEvent.PreUtterance + 8192 ); add.append( NRPN.CVM_EXNM_PRE_UTTERANCE, m.getKey(), m.getValue() ); } // Flags if ( ve.UstEvent.Flags != "" ) { char[] arr = ve.UstEvent.Flags.ToCharArray(); add.append( NRPN.CVM_EXNM_FLAGS_BYTES, (byte)arr.Length ); for ( int i = 0; i < arr.Length; i++ ) { byte b = (byte)arr[i]; add.append( NRPN.CVM_EXNM_FLAGS, b ); } add.append( NRPN.CVM_EXNM_FLAGS_CONINUATION, (byte)0x7f ); } // オーバーラップ if ( ve.UstEvent.VoiceOverlap != 0 ) { m = getMsbAndLsb( ve.UstEvent.VoiceOverlap + 8192 ); add.append( NRPN.CVM_EXNM_VOICE_OVERLAP, m.getKey(), m.getValue() ); } } } add.append( NRPN.CVM_NM_NOTE_MESSAGE_CONTINUATION, (byte)0x7f, true );// (byte)0x7f(Note message continuation) return add; } /// /// 指定したトラックのデータから,NRPNを作成します /// /// /// /// /// /// /// public static VsqNrpn[] generateNRPN( VsqFile vsq, int track, int msPreSend, int clock_start, int clock_end ) { VsqFile temp = (VsqFile)vsq.clone(); temp.removePart( clock_end, vsq.TotalClocks ); if ( 0 < clock_start ) { temp.removePart( 0, clock_start ); } temp.Master.PreMeasure = 1; //temp.m_premeasure_clocks = temp.getClockFromBarCount( 1 ); VsqNrpn[] ret = generateNRPN( temp, track, msPreSend ); temp = null; return ret; } /// /// 指定したトラックのデータから,NRPNを作成します /// /// /// /// /// public static VsqNrpn[] generateNRPN( VsqFile vsq, int track, int msPreSend ) { #if DEBUG PortUtil.println( "GenerateNRPN(VsqTrack,int,int,int,int)" ); #endif Vector list = new Vector(); VsqTrack target = vsq.Track.get( track ); String version = target.getCommon().Version; int count = target.getEventCount(); int note_start = 0; int note_end = target.getEventCount() - 1; for ( int i = 0; i < count; i++ ) { if ( 0 <= target.getEvent( i ).Clock ) { note_start = i; break; } note_start = i; } for ( int i = target.getEventCount() - 1; i >= 0; i-- ) { if ( target.getEvent( i ).Clock <= vsq.TotalClocks ) { note_end = i; break; } } // 最初の歌手を決める int singer_event = -1; for ( int i = note_start; i >= 0; i-- ) { if ( target.getEvent( i ).ID.type == VsqIDType.Singer ) { singer_event = i; break; } } if ( singer_event >= 0 ) { //見つかった場合 list.addAll( Arrays.asList( generateSingerNRPN( vsq, target.getEvent( singer_event ), 0 ) ) ); } else { //多分ありえないと思うが、歌手が不明の場合。 //throw new Exception( "first singer was not specified" ); list.add( new VsqNrpn( 0, NRPN.CC_BS_LANGUAGE_TYPE, (byte)0x0 ) ); list.add( new VsqNrpn( 0, NRPN.PC_VOICE_TYPE, (byte)0x0 ) ); } list.addAll( Arrays.asList( generateVoiceChangeParameterNRPN( vsq, track, msPreSend ) ) ); if ( version.StartsWith( "DSB2" ) ) { list.addAll( Arrays.asList( generateFx2DepthNRPN( vsq, track, msPreSend ) ) ); } int ms_presend = msPreSend; if ( version.StartsWith( "UTU0" ) ) { double sec_maxlen = 0.0; for ( Iterator itr = target.getNoteEventIterator(); itr.hasNext(); ) { VsqEvent ve = (VsqEvent)itr.next(); double len = vsq.getSecFromClock( ve.Clock + ve.ID.getLength() ) - vsq.getSecFromClock( ve.Clock ); sec_maxlen = Math.Max( sec_maxlen, len ); } ms_presend += (int)(sec_maxlen * 1000.0); } VsqBPList dyn = target.getCurve( "dyn" ); if ( dyn.size() > 0 ) { Vector listdyn = new Vector( Arrays.asList( generateExpressionNRPN( vsq, track, ms_presend ) ) ); if ( listdyn.size() > 0 ) { list.addAll( listdyn ); } } VsqBPList pbs = target.getCurve( "pbs" ); if ( pbs.size() > 0 ) { Vector listpbs = new Vector( Arrays.asList( generatePitchBendSensitivityNRPN( vsq, track, ms_presend ) ) ); if ( listpbs.size() > 0 ) { list.addAll( listpbs ); } } VsqBPList pit = target.getCurve( "pit" ); if ( pit.size() > 0 ) { Vector listpit = new Vector( Arrays.asList( generatePitchBendNRPN( vsq, track, ms_presend ) ) ); if ( listpit.size() > 0 ) { list.addAll( listpit ); } } boolean first = true; int last_note_end = 0; for ( int i = note_start; i <= note_end; i++ ) { VsqEvent item = target.getEvent( i ); if ( item.ID.type == VsqIDType.Anote ) { byte note_loc = (byte)0x03; if ( item.Clock == last_note_end ) { note_loc -= (byte)0x02; } // 次に現れる音符イベントを探す int nextclock = item.Clock + item.ID.getLength() + 1; int event_count = target.getEventCount(); for ( int j = i + 1; j < event_count; j++ ) { VsqEvent itemj = target.getEvent( j ); if ( itemj.ID.type == VsqIDType.Anote ) { nextclock = itemj.Clock; break; } } if ( item.Clock + item.ID.getLength() == nextclock ) { note_loc -= (byte)0x01; } list.add( generateNoteNRPN( vsq, track, item, msPreSend, note_loc, first ) ); first = false; list.addAll( Arrays.asList( generateVibratoNRPN( vsq, item, msPreSend ) ) ); last_note_end = item.Clock + item.ID.getLength(); } else if ( item.ID.type == VsqIDType.Singer ) { if ( i > note_start && i != singer_event ) { list.addAll( Arrays.asList( generateSingerNRPN( vsq, item, msPreSend ) ) ); } } } list = VsqNrpn.sort( list ); Vector merged = new Vector(); for ( int i = 0; i < list.size(); i++ ) { merged.addAll( Arrays.asList( list.get( i ).expand() ) ); } return merged.toArray( new VsqNrpn[] { } ); } /// /// 指定したトラックから、PitchBendのNRPNを作成します /// /// /// /// /// public static VsqNrpn[] generatePitchBendNRPN( VsqFile vsq, int track, int msPreSend ) { Vector ret = new Vector(); VsqBPList pit = vsq.Track.get( track ).getCurve( "PIT" ); int count = pit.size(); for ( int i = 0; i < count; i++ ) { int clock = pit.getKeyClock( i ); int value = pit.getElement( i ) + 0x2000; ValuePair val = getMsbAndLsb( value ); int c = clock - vsq.getPresendClockAt( clock, msPreSend ); if ( c >= 0 ) { VsqNrpn add = new VsqNrpn( c, NRPN.PB_PITCH_BEND, val.getKey(), val.getValue() ); ret.add( add ); } } return ret.toArray( new VsqNrpn[] { } ); } /// /// 指定したトラックからPitchBendSensitivityのNRPNを作成します /// /// /// /// /// public static VsqNrpn[] generatePitchBendSensitivityNRPN( VsqFile vsq, int track, int msPreSend ) { Vector ret = new Vector(); VsqBPList pbs = vsq.Track.get( track ).getCurve( "PBS" ); int count = pbs.size(); for ( int i = 0; i < count; i++ ) { int clock = pbs.getKeyClock( i ); int c = clock - vsq.getPresendClockAt( clock, msPreSend ); if ( c >= 0 ) { VsqNrpn add = new VsqNrpn( c, NRPN.CC_PBS_PITCH_BEND_SENSITIVITY, (byte)pbs.getElement( i ), (byte)0x00 ); ret.add( add ); } } return ret.toArray( new VsqNrpn[] { } ); } /// /// 指定した音符イベントから,ビブラート出力用のNRPNを作成します /// /// /// /// /// public static VsqNrpn[] generateVibratoNRPN( VsqFile vsq, VsqEvent ve, int msPreSend ) { Vector ret = new Vector(); if ( ve.ID.VibratoHandle != null ) { int vclock = ve.Clock + ve.ID.VibratoDelay; ValuePair del = getMsbAndLsb( msPreSend ); VsqNrpn add2 = new VsqNrpn( vclock - vsq.getPresendClockAt( vclock, msPreSend ), NRPN.CC_VD_VERSION_AND_DEVICE, (byte)0x00, (byte)0x00 ); add2.append( NRPN.CC_VD_DELAY, del.getKey(), del.getValue(), 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.getLength() - ve.ID.VibratoDelay; int count = ve.ID.VibratoHandle.RateBP.getCount(); if ( count > 0 ) { for ( int i = 0; i < count; i++ ) { float percent = ve.ID.VibratoHandle.RateBP.getElement( i ).X; int cl = vclock + (int)(percent * vlength); ret.add( new VsqNrpn( cl - vsq.getPresendClockAt( cl, msPreSend ), NRPN.CC_VR_VIBRATO_RATE, (byte)ve.ID.VibratoHandle.RateBP.getElement( i ).Y ) ); } } count = ve.ID.VibratoHandle.DepthBP.getCount(); if ( count > 0 ) { for ( int i = 0; i < count; i++ ) { float percent = ve.ID.VibratoHandle.DepthBP.getElement( i ).X; int cl = vclock + (int)(percent * vlength); ret.add( new VsqNrpn( cl - vsq.getPresendClockAt( cl, msPreSend ), NRPN.CC_VD_VIBRATO_DEPTH, (byte)ve.ID.VibratoHandle.DepthBP.getElement( i ).Y ) ); } } } Collections.sort( ret ); return ret.toArray( new VsqNrpn[] { } ); } /// /// 指定したトラックから、VoiceChangeParameterのNRPNのリストを作成します /// /// /// /// /// public static VsqNrpn[] generateVoiceChangeParameterNRPN( VsqFile vsq, int track, int msPreSend ) { int premeasure_clock = vsq.getPreMeasureClocks(); String renderer = vsq.Track.get( track ).getCommon().Version; Vector res = new Vector(); String[] curves; if ( renderer.StartsWith( "DSB3" ) ) { curves = new String[] { "BRE", "BRI", "CLE", "POR", "OPE", "GEN" }; } else if ( renderer.StartsWith( "DSB2" ) ) { curves = new String[] { "BRE", "BRI", "CLE", "POR", "GEN", "harmonics", "reso1amp", "reso1bw", "reso1freq", "reso2amp", "reso2bw", "reso2freq", "reso3amp", "reso3bw", "reso3freq", "reso4amp", "reso4bw", "reso4freq" }; } else { curves = new String[] { "BRE", "BRI", "CLE", "POR", "GEN" }; } for ( int i = 0; i < curves.Length; i++ ) { VsqBPList vbpl = vsq.Track.get( track ).getCurve( curves[i] ); if ( vbpl.size() > 0 ) { byte lsb = NRPN.getVoiceChangeParameterID( curves[i] ); int count = vbpl.size(); for ( int j = 0; j < count; j++ ) { int clock = vbpl.getKeyClock( j ); int c = clock - vsq.getPresendClockAt( clock, msPreSend ); if ( c >= 0 ) { VsqNrpn add = new VsqNrpn( c, NRPN.VCP_VOICE_CHANGE_PARAMETER_ID, lsb ); add.append( NRPN.VCP_VOICE_CHANGE_PARAMETER, (byte)vbpl.getElement( j ), true ); res.add( add ); } } } } Collections.sort( res ); return res.toArray( new VsqNrpn[] { } ); } private static ValuePair getMsbAndLsb( int value ) { ValuePair ret = new ValuePair(); if ( 0x3fff < value ) { ret.setKey( (byte)0x7f ); ret.setValue( (byte)0x7f ); } else { byte msb = (byte)(value >> 7); ret.setKey( msb ); ret.setValue( (byte)(value - (msb << 7)) ); } return ret; } public Vector generateTimeSig() { Vector events = new Vector(); for ( Iterator itr = TimesigTable.iterator(); itr.hasNext(); ) { TimeSigTableEntry entry = (TimeSigTableEntry)itr.next(); events.add( MidiEvent.generateTimeSigEvent( entry.Clock, entry.Numerator, entry.Denominator ) ); } return events; } public Vector generateTempoChange() { Vector events = new Vector(); for ( Iterator itr = TempoTable.iterator(); itr.hasNext(); ) { TempoTableEntry entry = (TempoTableEntry)itr.next(); events.add( MidiEvent.generateTempoChangeEvent( entry.Clock, entry.Tempo ) ); //last_clock = Math.Max( last_clock, entry.Clock ); } return events; } /// /// このインスタンスをファイルに出力します /// /// public void write( String file ) { write( file, 500, "Shift_JIS" ); } /// /// このインスタンスをファイルに出力します /// /// /// プリセンドタイム(msec) public void write( String file, int msPreSend, String encoding ) { #if DEBUG PortUtil.println( "VsqFile.Write(String)" ); #endif int last_clock = 0; int track_size = Track.size(); for ( int track = 1; track < track_size; track++ ) { if ( Track.get( track ).getEventCount() > 0 ) { int index = Track.get( track ).getEventCount() - 1; VsqEvent last = Track.get( track ).getEvent( index ); last_clock = Math.Max( last_clock, last.Clock + last.ID.getLength() ); } } if ( PortUtil.isFileExists( file ) ) { try { PortUtil.deleteFile( file ); } catch ( Exception ex ) { } } RandomAccessFile fs = null; try { fs = new RandomAccessFile( file, "rw" ); long first_position;//チャンクの先頭のファイル位置 #region ヘッダ //チャンクタイプ fs.write( _MTHD, 0, 4 ); //データ長 fs.write( (byte)0x00 ); fs.write( (byte)0x00 ); fs.write( (byte)0x00 ); fs.write( (byte)0x06 ); //フォーマット fs.write( (byte)0x00 ); fs.write( (byte)0x01 ); //トラック数 writeUnsignedShort( fs, Track.size() ); //時間単位 fs.write( (byte)0x01 ); fs.write( (byte)0xe0 ); #endregion #region Master Track //チャンクタイプ fs.write( _MTRK, 0, 4 ); //データ長。とりあえず0を入れておく fs.write( new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, 0, 4 ); first_position = fs.getFilePointer(); //トラック名 writeFlexibleLengthUnsignedLong( fs, 0 );//デルタタイム fs.write( (byte)0xff );//ステータスタイプ fs.write( (byte)0x03 );//イベントタイプSequence/Track Name fs.write( (byte)_MASTER_TRACK.Length );//トラック名の文字数。これは固定 fs.write( _MASTER_TRACK, 0, _MASTER_TRACK.Length ); Vector events = new Vector(); for ( Iterator itr = TimesigTable.iterator(); itr.hasNext(); ) { TimeSigTableEntry entry = (TimeSigTableEntry)itr.next(); events.add( MidiEvent.generateTimeSigEvent( entry.Clock, entry.Numerator, entry.Denominator ) ); last_clock = Math.Max( last_clock, entry.Clock ); } for ( Iterator itr = TempoTable.iterator(); itr.hasNext(); ) { TempoTableEntry entry = (TempoTableEntry)itr.next(); events.add( MidiEvent.generateTempoChangeEvent( entry.Clock, entry.Tempo ) ); last_clock = Math.Max( last_clock, entry.Clock ); } #if DEBUG PortUtil.println( " events.Count=" + events.size() ); #endif Collections.sort( events ); long last = 0; for ( Iterator itr = events.iterator(); itr.hasNext(); ) { MidiEvent me = (MidiEvent)itr.next(); #if DEBUG PortUtil.println( "me.Clock=" + me.clock ); #endif writeFlexibleLengthUnsignedLong( fs, (long)(me.clock - last) ); me.writeData( fs ); last = me.clock; } //WriteFlexibleLengthUnsignedLong( fs, (ulong)(last_clock + 120 - last) ); writeFlexibleLengthUnsignedLong( fs, 0 ); fs.write( (byte)0xff ); fs.write( (byte)0x2f );//イベントタイプEnd of Track fs.write( (byte)0x00 ); long pos = fs.getFilePointer(); fs.seek( first_position - 4 ); writeUnsignedInt( fs, pos - first_position ); fs.seek( pos ); #endregion #region トラック VsqFile temp = (VsqFile)this.clone(); temp.Track.get( 1 ).setMaster( (VsqMaster)Master.clone() ); temp.Track.get( 1 ).setMixer( (VsqMixer)Mixer.clone() ); printTrack( temp, 1, fs, msPreSend, encoding ); int count = Track.size(); for ( int track = 2; track < count; track++ ) { printTrack( this, track, fs, msPreSend, encoding ); } #endregion } catch ( Exception ex ) { } finally { if ( fs != null ) { try { fs.close(); } catch ( Exception ex2 ) { } } } } /// /// メタテキストの行番号から、各行先頭のプレフィクス文字列("DM:0123:"等)を作成します /// /// /// public static String getLinePrefix( int count ) { int digits = getHowManyDigits( count ); int c = (digits - 1) / 4 + 1; String format = ""; for ( int i = 0; i < c; i++ ) { format += "0000"; } return "DM:" + PortUtil.formatDecimal( format, count ) + ":"; } public static byte[] getLinePrefixBytes( int count ) { int digits = getHowManyDigits( count ); int c = (digits - 1) / 4 + 1; String format = ""; for ( int i = 0; i < c; i++ ) { format += "0000"; } String str = "DM:" + PortUtil.formatDecimal( format, count ) + ":"; byte[] ret = PortUtil.getEncodedByte( "ASCII", str ); return ret; } /// /// 数numberの桁数を調べます。(10進数のみ) /// /// /// private static int getHowManyDigits( int number ) { int val; if ( number > 0 ) { val = number; } else { val = -number; } int i = 1; int digits = 1; while ( true ) { i++; digits *= 10; if ( val < digits ) { return i - 1; } } } /// /// char[]を書き込む。 /// /// /// public static void writeCharArray( RandomAccessFile fs, char[] item ) #if JAVA throws IOException #endif { for ( int i = 0; i < item.Length; i++ ) { fs.write( (byte)item[i] ); } } /// /// ushort値をビッグエンディアンでfsに書き込みます /// /// public static void writeUnsignedShort( RandomAccessFile fs, int data ) #if JAVA throws IOException #endif { byte[] dat = PortUtil.getbytes_uint16_be( data ); fs.write( dat, 0, dat.Length ); } /// /// uint値をビッグエンディアンでfsに書き込みます /// /// public static void writeUnsignedInt( RandomAccessFile fs, long data ) #if JAVA throws IOException #endif { byte[] dat = PortUtil.getbytes_uint32_be( data ); fs.write( dat, 0, dat.Length ); } /// /// SMFの可変長数値表現を使って、ulongをbyte[]に変換します /// /// public static byte[] getBytesFlexibleLengthUnsignedLong( long number ) { boolean[] bits = new boolean[64]; long val = (byte)0x1; bits[0] = (number & val) == val; for ( int i = 1; i < 64; i++ ) { val = val << 1; bits[i] = (number & val) == val; } int first = 0; for ( int i = 63; i >= 0; i-- ) { if ( bits[i] ) { first = i; break; } } // 何バイト必要か? int bytes = first / 7 + 1; byte[] ret = new byte[bytes]; for ( int i = 1; i <= bytes; i++ ) { int num = 0; int count = (byte)0x80; for ( int j = (bytes - i + 1) * 7 - 1; j >= (bytes - i + 1) * 7 - 6 - 1; j-- ) { count = count >> 1; if ( bits[j] ) { num += count; } } if ( i != bytes ) { num += (byte)0x80; } ret[i - 1] = (byte)num; } return ret; } /// /// 整数を書き込む。フォーマットはSMFの可変長数値表現。 /// /// /// public static void writeFlexibleLengthUnsignedLong( RandomAccessFile fs, long number ) #if JAVA throws IOException #endif { byte[] bytes = getBytesFlexibleLengthUnsignedLong( number ); fs.write( bytes, 0, bytes.Length ); } } #if !JAVA } #endif