/* * 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. */ using System; using System.Collections.Generic; using System.IO; namespace Boare.Lib.Vsq { /// /// Stores the data of a vsq track. /// [Serializable] public partial class VsqTrack : ICloneable { public string Tag; /// /// トラックの名前。 /// public string Name; public VsqMetaText MetaText; private int m_edited_start = int.MaxValue; private int m_edited_end = int.MinValue; private class SingerEventIterator : Iterator { VsqEventList m_list; int m_pos; public SingerEventIterator( VsqEventList list ) { m_list = list; m_pos = -1; } public bool 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 ); } } } private class NoteEventIterator : Iterator { VsqEventList m_list; int m_pos; public NoteEventIterator( VsqEventList list ) { m_list = list; m_pos = -1; } public bool hasNext() { for ( int i = m_pos + 1; i < m_list.getCount(); i++ ) { if ( m_list.getElement( i ).ID.type == VsqIDType.Anote ) { 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.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 ); } } } private class EventIterator : Iterator{ 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 ); } } } /// /// ピッチベンド。Cent単位 /// /// /// public double getPitchAt( int clock ) { double inv2_13 = 1.0 / 8192.0; int pit = MetaText.PIT.getValue( clock ); int pbs = MetaText.PBS.getValue( clock ); return (double)pit * (double)pbs * inv2_13 * 100.0; } public void sortEvent() { MetaText.Events.sort(); } /// /// 歌手変更イベントを,曲の先頭から順に返す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 ) { MetaText.print( sw, false, eos, start ); } /// /// メタテキストを,指定されたファイルに出力します /// /// public void printMetaText( string file ) { TextMemoryStream tms = new TextMemoryStream(); int count = MetaText.getEventList().getCount(); int clLast = MetaText.getEventList().getElement( count - 1 ).Clock + 480; MetaText.print( tms, true, clLast, 0 ); using ( StreamWriter sw = new StreamWriter( file ) ) { tms.rewind(); while ( tms.peek() >= 0 ) { string line = tms.readLine(); sw.WriteLine( line ); } } } /// /// Masterを取得します /// public VsqMaster getMaster() { return MetaText.master; } internal void setMaster( VsqMaster value ) { MetaText.master = value; } /// /// Mixerを取得します /// public VsqMixer getMixer() { return MetaText.mixer; } internal void setMixer( VsqMixer value ) { MetaText.mixer = value; } /// /// Commonを取得します /// /// public VsqCommon getCommon() { return MetaText.Common; } /// /// 指定したトラックのレンダラーを変更します /// /// /// /// public void changeRenderer( string new_renderer, List singers ) { VsqID default_id = null; if ( singers.Count <= 0 ) { default_id = new VsqID(); default_id.type = VsqIDType.Singer; default_id.IconHandle = new IconHandle(); default_id.IconHandle.IconID = "$0701" + 0.ToString( "0000" ); default_id.IconHandle.IDS = "Unknown"; default_id.IconHandle.Index = 0; default_id.IconHandle.Language = 0; default_id.IconHandle.Length = 1; default_id.IconHandle.Original = 0; default_id.IconHandle.Program = 0; default_id.IconHandle.Caption = ""; } else { default_id = singers[0]; } for ( Iterator itr = getSingerEventIterator(); itr.hasNext(); ) { VsqEvent ve = (VsqEvent)itr.next(); int program = ve.ID.IconHandle.Program; bool found = false; for ( int i = 0; i < singers.Count; i++ ) { if ( program == singers[i].IconHandle.Program ) { ve.ID = (VsqID)singers[i].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.Name = Name; 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; } /// /// Master Trackを構築 /// /// /// /// public VsqTrack( int tempo, int numerator, int denominator ) { this.Name = "Master Track"; this.MetaText = null; } /// /// Master Trackでないトラックを構築。 /// /// /// public VsqTrack( string name, string singer ) { Name = name; MetaText = new VsqMetaText( name, singer ); } public VsqTrack() : this( "Voice1", "Miku" ) { } /// /// 歌詞の文字数を調べます /// /// 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( List midi_event ) { Name = ""; #if DEBUG bocoree.debug.push_log( "VsqTrack..ctor" ); #endif using ( TextMemoryStream sw = new TextMemoryStream() ) { for ( int i = 0; i < midi_event.Count; i++ ) { if ( midi_event[i].firstByte == 0xff && midi_event[i].data.Length > 0 ) { // meta textを抽出 byte type = midi_event[i].data[0]; if ( type == 0x01 || type == 0x03 ) { char[] ch = new char[midi_event[i].data.Length - 1]; for ( int j = 1; j < midi_event[i].data.Length; j++ ) { ch[j - 1] = (char)midi_event[i].data[j]; } string line = new string( ch ); if ( type == 0x01 ) { int second_colon = line.IndexOf( ':', 3 ); line = line.Substring( second_colon + 1 ); line = line.Replace( "\\n", "\n" ); //line = line.Replace( "\n", Environment.NewLine ); string[] lines = line.Split( '\n' ); int c = lines.Length; for ( int j = 0; j < c; j++ ) { if ( j < c - 1 ) { sw.writeLine( lines[j] ); } else { sw.write( lines[j] ); } } //sw.write( line ); } else { Name = line; } } } else { continue; } } sw.rewind(); MetaText = new VsqMetaText( sw ); } } } }