/*
* 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;
using System.Text;
using bocoree;
namespace Boare.Lib.Vsq {
using boolean = System.Boolean;
///
/// 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 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 );
}
}
}
private class NoteEventIterator : Iterator {
VsqEventList m_list;
int m_pos;
public NoteEventIterator( 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.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 );
}
}
}
public String getName() {
if ( MetaText == null ) {
return "Master Track";
} else {
return MetaText.Common.Name;
}
}
public void setName( String value ) {
if ( MetaText != null ) {
MetaText.Common.Name = value;
}
}
[Obsolete]
public String Name {
get {
return getName();
}
set {
setName( value );
}
}
///
/// ピッチベンド。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 ) {
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, Vector singers ) {
VsqID default_id = null;
if ( singers.size() <= 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.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++ ) {
if ( program == singers.get( i ).IconHandle.Program ) {
ve.ID = (VsqID)singers.get( 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.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;
}
public object Clone() {
return clone();
}
///
/// 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 );
}
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( Vector midi_event, Encoding encoding ) {
#if DEBUG
bocoree.debug.push_log( "VsqTrack..ctor" );
#endif
String track_name = "";
using ( TextMemoryStream sw = new TextMemoryStream() ) {
for ( int i = 0; i < midi_event.size(); i++ ) {
if ( midi_event.get( i ).firstByte == 0xff && midi_event.get( i ).data.Length > 0 ) {
// meta textを抽出
byte type = midi_event.get( i ).data[0];
if ( type == 0x01 || type == 0x03 ) {
/*char[] ch = new char[midi_event.get( i ).data.Length - 1];
for ( int j = 1; j < midi_event.get( i ).data.Length; j++ ) {
ch[j - 1] = (char)midi_event.get( i ).data[j];
}
String line = new String( ch );*/
byte[] dat = midi_event.get( i ).data;
String line = encoding.GetString( dat, 1, dat.Length - 1 );
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 {
track_name = line;
}
}
} else {
continue;
}
}
sw.rewind();
MetaText = new VsqMetaText( sw );
setName( track_name );
}
}
}
}