/* * VsqTrack.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. */ #if JAVA package org.kbinani.vsq; import java.io.*; import java.util.*; import org.kbinani.*; #else using System; using bocoree; using bocoree.java.util; using bocoree.java.io; namespace Boare.Lib.Vsq { using boolean = System.Boolean; #endif /// /// Stores the data of a vsq track. /// #if JAVA public class VsqTrack implements Cloneable, Serializable { #else [Serializable] public class VsqTrack : ICloneable { #endif public String Tag; /// /// トラックの名前。 /// //public String Name; public VsqMetaText MetaText; private int m_edited_start = int.MaxValue; private int m_edited_end = int.MinValue; #if JAVA private class SingerEventIterator implements Iterator{ #else private class SingerEventIterator : Iterator { #endif VsqEventList m_list; int m_pos; public SingerEventIterator( VsqEventList list ) { m_list = list; m_pos = -1; } public boolean hasNext() { for ( int i = m_pos + 1; i < m_list.getCount(); i++ ) { if ( m_list.getElement( i ).ID.type == VsqIDType.Singer ) { return true; } } return false; } public Object next() { for ( int i = m_pos + 1; i < m_list.getCount(); i++ ) { VsqEvent item = m_list.getElement( i ); if ( item.ID.type == VsqIDType.Singer ) { m_pos = i; return item; } } return null; } public void remove() { if ( 0 <= m_pos && m_pos < m_list.getCount() ) { m_list.removeAt( m_pos ); } } } #if JAVA private class NoteEventIterator implements Iterator{ #else private class NoteEventIterator : Iterator { #endif VsqEventList m_list; int m_pos; public NoteEventIterator( VsqEventList list ) { m_list = list; m_pos = -1; } public boolean hasNext() { int count = m_list.getCount(); for ( int i = m_pos + 1; i < count; i++ ) { if ( m_list.getElement( i ).ID.type == VsqIDType.Anote ) { return true; } } return false; } public Object next() { int count = m_list.getCount(); for ( int i = m_pos + 1; i < count; i++ ) { VsqEvent item = m_list.getElement( i ); if ( item.ID.type == VsqIDType.Anote ) { m_pos = i; return item; } } return null; } public void remove() { if ( 0 <= m_pos && m_pos < m_list.getCount() ) { m_list.removeAt( m_pos ); } } } #if JAVA private class EventIterator implements Iterator{ #else private class EventIterator : Iterator { #endif private VsqEventList m_list; private int m_pos; public EventIterator( VsqEventList list ) { m_list = list; m_pos = -1; } public boolean hasNext() { if ( 0 <= m_pos + 1 && m_pos + 1 < m_list.getCount() ) { return true; } return false; } public Object next() { m_pos++; return m_list.getElement( m_pos ); } public void remove() { if ( 0 <= m_pos && m_pos < m_list.getCount() ) { m_list.removeAt( m_pos ); } } } public String getName() { if ( MetaText == null || (MetaText != null && MetaText.Common == null) ) { return "Master Track"; } else { return MetaText.Common.Name; } } public void setName( String value ) { if ( MetaText != null ) { if ( MetaText.Common == null ) { MetaText.Common = new VsqCommon(); } MetaText.Common.Name = value; } } #if !JAVA [Obsolete] public String Name { get { return getName(); } set { setName( value ); } } #endif /// /// ピッチベンド。Cent単位 /// /// /// public double getPitchAt( int clock ) { double inv2_13 = 1.0 / 8192.0; int pit = MetaText.PIT.getValue( clock ); int pbs = MetaText.PBS.getValue( clock ); return (double)pit * (double)pbs * inv2_13 * 100.0; } /// /// 指定したクロック位置において、歌唱を担当している歌手のVsqEventを返します。 /// /// /// public VsqEvent getSingerEventAt( int clock ) { VsqEvent last = null; for ( Iterator itr = getSingerEventIterator(); itr.hasNext(); ) { VsqEvent item = (VsqEvent)itr.next(); if ( clock < item.Clock ) { return last; } last = item; } return last; } public void sortEvent() { MetaText.Events.sort(); } /// /// 歌手変更イベントを,曲の先頭から順に返すIteratorを取得します /// /// public Iterator getSingerEventIterator() { return new SingerEventIterator( MetaText.getEventList() ); } /// /// 音符イベントを,曲の先頭から順に返すIteratorを取得します /// /// public Iterator getNoteEventIterator() { if ( MetaText == null ) { return new NoteEventIterator( new VsqEventList() ); } else { return new NoteEventIterator( MetaText.getEventList() ); } } /// /// メタテキストを,メモリー上のストリームに出力します /// /// /// /// /// public void printMetaText( TextMemoryStream sw, int eos, int start ) #if JAVA throws IOException #endif { MetaText.print( sw, eos, start ); } /// /// メタテキストを,指定されたファイルに出力します /// /// public void printMetaText( String file ) #if JAVA throws IOException #endif { TextMemoryStream tms = new TextMemoryStream(); int count = MetaText.getEventList().getCount(); int clLast = MetaText.getEventList().getElement( count - 1 ).Clock + 480; MetaText.print( tms, clLast, 0 ); BufferedWriter sw = null; try { sw = new BufferedWriter( new FileWriter( file ) ); tms.rewind(); while ( tms.peek() >= 0 ) { String line = tms.readLine(); sw.write( line ); sw.newLine(); } } catch ( Exception ex ) { } finally { if ( sw != null ) { try { sw.close(); } catch ( Exception ex2 ) { } } } } /// /// Masterを取得します /// public VsqMaster getMaster() { return MetaText.master; } public void setMaster( VsqMaster value ) { MetaText.master = value; } /// /// Mixerを取得します /// public VsqMixer getMixer() { return MetaText.mixer; } public void setMixer( VsqMixer value ) { MetaText.mixer = value; } /// /// Commonを取得します /// /// public VsqCommon getCommon() { return MetaText.Common; } /// /// 指定したトラックのレンダラーを変更します /// /// /// /// public void changeRenderer( String new_renderer, Vector singers ) { VsqID default_id = null; int singers_size = singers.size(); if ( singers_size <= 0 ) { default_id = new VsqID(); default_id.type = VsqIDType.Singer; default_id.IconHandle = new IconHandle(); default_id.IconHandle.IconID = "$0701" + PortUtil.toHexString( 0, 4 ); default_id.IconHandle.IDS = "Unknown"; default_id.IconHandle.Index = 0; default_id.IconHandle.Language = 0; default_id.IconHandle.setLength( 1 ); default_id.IconHandle.Original = 0; default_id.IconHandle.Program = 0; default_id.IconHandle.Caption = ""; } else { default_id = singers.get( 0 ); } for ( Iterator itr = getSingerEventIterator(); itr.hasNext(); ) { VsqEvent ve = (VsqEvent)itr.next(); int program = ve.ID.IconHandle.Program; boolean found = false; for ( int i = 0; i < singers_size; i++ ) { VsqID id = singers.get( i ); if ( program == id.IconHandle.Program ) { ve.ID = (VsqID)id.clone(); found = true; break; } } if ( !found ) { VsqID add = (VsqID)default_id.clone(); add.IconHandle.Program = program; ve.ID = add; } } MetaText.Common.Version = new_renderer; } /// /// このトラックが保持している,指定されたカーブのBPListを取得します /// /// /// public VsqBPList getCurve( String curve ) { return MetaText.getElement( curve ); } public void setCurve( String curve, VsqBPList value ) { MetaText.setElement( curve, value ); } public int getEventCount() { return MetaText.getEventList().getCount(); } public VsqEvent getEvent( int index ) { return MetaText.getEventList().getElement( index ); } public VsqEvent findEventFromID( int internal_id ) { return MetaText.getEventList().findFromID( internal_id ); } public void setEvent( int index, VsqEvent item ) { MetaText.getEventList().setElement( index, item ); } public void addEvent( VsqEvent item ) { MetaText.getEventList().add( item ); } public Iterator getEventIterator() { return new EventIterator( MetaText.getEventList() ); } public void removeEvent( int index ) { MetaText.getEventList().removeAt( index ); } /// /// このトラックの,最後に編集が加えられた範囲の,開始位置(クロック)を取得します. /// public int getEditedStart() { return m_edited_start; } public void setEditedStart( int value ) { if ( value < m_edited_start ) { m_edited_start = value; } } /// /// このトラックの,最後に編集が加えられた範囲の,終了位置(クロック)を取得します. /// public int getEditedEnd() { return m_edited_end; } public void setEditedEnd( int value ) { if ( m_edited_end < value ) { m_edited_end = value; } } /// /// このトラックの,編集範囲(EditedStart, EditedEnd)をリセットします. /// public void resetEditedArea() { m_edited_start = int.MaxValue; m_edited_end = int.MinValue; } /// /// このインスタンスのコピーを作成します /// /// public Object clone() { VsqTrack res = new VsqTrack(); res.setName( getName() ); if ( MetaText != null ) { res.MetaText = (VsqMetaText)MetaText.clone(); } res.m_edited_start = m_edited_start; res.m_edited_end = m_edited_end; res.Tag = Tag; return res; } #if !JAVA public object Clone() { return clone(); } #endif /// /// Master Trackを構築 /// /// /// /// public VsqTrack( int tempo, int numerator, int denominator ) { //this.Name = "Master Track"; // metatextがnullのとき,トラック名はMaster Track this.MetaText = null; } /// /// Master Trackでないトラックを構築。 /// /// /// public VsqTrack( String name, String singer ) { MetaText = new VsqMetaText( name, singer ); } #if JAVA public VsqTrack(){ this( "Voice1", "Miku" ); #else public VsqTrack() : this( "Voice1", "Miku" ) { #endif } /// /// 歌詞の文字数を調べます /// /// public int getLyricLength() { int counter = 0; for ( int i = 0; i < MetaText.getEventList().getCount(); i++ ) { if ( MetaText.getEventList().getElement( i ).ID.type == VsqIDType.Anote ) { counter++; } } return counter; } public VsqTrack( Vector midi_event, String encoding ) { #if DEBUG bocoree.debug.push_log( "VsqTrack..ctor" ); #endif String track_name = ""; TextMemoryStream sw = null; try { sw = new TextMemoryStream(); int count = midi_event.size(); Vector buffer = new Vector(); for ( int i = 0; i < count; i++ ) { MidiEvent item = midi_event.get( i ); if ( item.firstByte == 0xff && item.data.Length > 0 ) { // meta textを抽出 byte type = item.data[0]; if ( type == 0x01 || type == 0x03 ) { //String line = PortUtil.getDecodedString( encoding, dat, 1, dat.Length - 1 ); if ( type == 0x01 ) { int colon_count = 0; for ( int j = 0; j < item.data.Length - 1; j++ ) { byte d = item.data[j + 1]; if ( d == 0x3a ) { colon_count++; if ( colon_count <= 2 ) { continue; } } if ( colon_count < 2 ) { continue; } buffer.add( d ); } int index_0x0a = buffer.indexOf( 0x0a ); while ( index_0x0a >= 0 ) { byte[] cpy = new byte[index_0x0a]; for ( int j = 0; j < index_0x0a; j++ ) { cpy[j] = buffer.get( 0 ); buffer.removeElementAt( 0 ); } String line = PortUtil.getDecodedString( encoding, cpy ); sw.writeLine( line ); buffer.removeElementAt( 0 ); index_0x0a = buffer.indexOf( 0x0a ); } /*int second_colon = line.IndexOf( ':', 3 ); line = line.Substring( second_colon + 1 ); line = line.Replace( "\\n", "\n" ); String[] lines = PortUtil.splitString( line, '\n' ); int c = lines.Length; for ( int j = 0; j < c; j++ ) { if ( j < c - 1 ) { sw.writeLine( lines[j] ); } else { sw.write( lines[j] ); } }*/ } else { for ( int j = 0; j < item.data.Length - 1; j++ ) { buffer.add( item.data[j + 1] ); } track_name = PortUtil.getDecodedString( encoding, PortUtil.convertByteArray( buffer.toArray( new Byte[] { } ) ) ); #if DEBUG Console.WriteLine( "VsqTrack#.ctor; track_name=" + track_name ); #endif buffer.clear(); } } } else { continue; } } sw.rewind(); MetaText = new VsqMetaText( sw ); setName( track_name ); } catch ( Exception ex ) { PortUtil.println( "com.boare.vsq.VsqTrack#.ctor; ex=" + ex ); } finally { if ( sw != null ) { try { sw.close(); } catch ( Exception ex2 ) { } } } } } #if !JAVA } #endif