/* * 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 object Tag; /// /// トラックの名前。 /// public string Name; private VsqMetaText m_meta_text; private List m_midi_event; private int m_edited_start = int.MaxValue; private int m_edited_end = int.MinValue; public string Renderer = "VOCALOID2"; 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 ); } } } /// /// 歌手変更イベントを,曲の先頭から順に返すIteratorを取得します /// /// public Iterator getSingerEventIterator() { return new SingerEventIterator( m_meta_text.getEventList() ); } /// /// 音符イベントを,曲の先頭から順に返すIteratorを取得します /// /// public Iterator getNoteEventIterator() { return new NoteEventIterator( m_meta_text.getEventList() ); } /// /// メタテキストを,メモリー上のストリームに出力します /// /// /// /// /// public void printMetaText( TextMemoryStream sw, int eos, int start ) { m_meta_text.print( sw, false, eos, start ); } /// /// メタテキストを,指定されたファイルに出力します /// /// public void printMetaText( string file ) { TextMemoryStream tms = new TextMemoryStream( FileAccess.ReadWrite ); int count = m_meta_text.getEventList().getCount(); int clLast = m_meta_text.getEventList().getElement( count - 1 ).Clock + 480; m_meta_text.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 m_meta_text.master; } internal void setMaster( VsqMaster value ) { m_meta_text.master = value; } /// /// Mixerを取得します /// public VsqMixer getMixer() { return m_meta_text.mixer; } internal void setMixer( VsqMixer value ) { m_meta_text.mixer = value; } /// /// このトラックが保持している,指定されたカーブのBPListを取得します /// /// /// public VsqBPList getCurve( string curve ) { return m_meta_text.getElement( curve ); } public void setCurve( string curve, VsqBPList value ) { m_meta_text.setElement( curve, value ); } public int getEventCount() { return m_meta_text.getEventList().getCount(); } public VsqEvent getEvent( int index ) { return m_meta_text.getEventList().getElement( index ); } public void setEvent( int index, VsqEvent item ) { m_meta_text.getEventList().setElement( index, item ); } public void addEvent( VsqEvent item ) { m_meta_text.getEventList().add( item ); } public Iterator getEventIterator() { return new EventIterator( m_meta_text.getEventList() ); } public void removeEvent( int index ) { m_meta_text.getEventList().removeAt( index ); } /// /// このトラックの,最後に編集が加えられた範囲の,開始位置(クロック)を取得します. /// このインスタンスを保持しているVsqFileインスタンスのExecuteメソッドによって自動的に更新されます /// public int getEditedStart() { return m_edited_start; } internal void setEditedStart( int value ) { if ( value < m_edited_start ) { m_edited_start = value; } } /// /// このトラックの,最後に編集が加えられた範囲の,終了位置(クロック)を取得します. /// このインスタンスを保持しているVsqFileインスタンスのExecuteメソッドによって自動的に更新されます /// public int getEditedEnd() { return m_edited_end; } internal 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 ( m_meta_text != null ) { res.m_meta_text = (VsqMetaText)m_meta_text.Clone(); } if ( m_midi_event != null ) { res.m_midi_event = new List( m_midi_event ); } res.m_edited_start = m_edited_start; res.m_edited_end = m_edited_end; res.Renderer = Renderer; return res; } private VsqTrack() { } /// /// Master Trackを構築 /// /// /// /// public VsqTrack( int tempo, int numerator, int denominator ) { this.Name = "Master Track"; this.m_meta_text = null; m_midi_event = new List(); // テンポを設定 MidiEvent mi_tempo = new MidiEvent(); mi_tempo.Clock = 0; mi_tempo.FirstByte = 0xff; byte b1 = (byte)(tempo & 0xff); tempo = tempo >> 8; byte b2 = (byte)(tempo & 0xff); tempo = tempo >> 8; byte b3 = (byte)(tempo & 0xff); mi_tempo.Data = new byte[5] { 0x51, 0x03, b3, b2, b1 }; m_midi_event.Add( mi_tempo ); // 拍子を設定 MidiEvent mi_timesig = MidiEvent.generateTimeSigEvent( 0, numerator, denominator ); m_midi_event.Add( mi_timesig ); } /// /// Master Trackでないトラックを構築。 /// /// /// public VsqTrack( string name, string singer ) { Name = name; m_meta_text = new VsqMetaText( name, singer ); m_midi_event = new List(); } /// /// 歌詞の文字数を調べます /// /// public int getLyricLength() { int counter = 0; for ( int i = 0; i < m_meta_text.getEventList().getCount(); i++ ) { if ( m_meta_text.getEventList().getElement( i ).ID.type == VsqIDType.Anote ) { counter++; } } return counter; } public VsqTrack( List midi_events ) { m_midi_event = new List( midi_events ); Name = ""; #if DEBUG bocoree.debug.push_log( "VsqTrack..ctor" ); #endif using ( TextMemoryStream sw = new TextMemoryStream() ) { for ( int i = 0; i < m_midi_event.Count; i++ ) { if ( m_midi_event[i].FirstByte == 0xff && m_midi_event[i].Data.Length > 0 ) { // meta textを抽出 byte type = m_midi_event[i].Data[0]; if ( type == 0x01 || type == 0x03 ) { char[] ch = new char[m_midi_event[i].Data.Length - 1]; for ( int j = 1; j < midi_events[i].Data.Length; j++ ) { ch[j - 1] = (char)midi_events[i].Data[j]; } string line = new string( ch ); if ( type == 0x01 ) { int second_colon = line.IndexOf( ':', 3 ); line = line.Substring( second_colon + 1 ); line = line.Replace( "\\n", Environment.NewLine ); line = line.Replace( "\n", Environment.NewLine ); sw.write( line ); } else { Name = line; } } } else { continue; } } sw.rewind(); m_meta_text = new VsqMetaText( sw ); } } public List getTempoList() { List list = new List(); for ( int i = 0; i < m_midi_event.Count; i++ ) { if ( m_midi_event[i].FirstByte == 0xff && m_midi_event[i].Data.Length >= 4 && m_midi_event[i].Data[0] == 0x51 ) { list.Add( m_midi_event[i] ); } } return list; } /// /// MidiEventの中から拍子情報を抽出します /// /// public List getTimeSigList() { List list = new List(); for ( int i = 0; i < m_midi_event.Count; i++ ) { if ( m_midi_event[i].FirstByte == 0xff && m_midi_event[i].Data.Length >= 5 && m_midi_event[i].Data[0] == 0x58 ) { list.Add( m_midi_event[i] ); } } return list; } } }