lipsync/trunk/Boare.Lib.Vsq/VsqTrack.cs

414 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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 {
/// <summary>
/// Stores the data of a vsq track.
/// </summary>
[Serializable]
public partial class VsqTrack : ICloneable {
public object Tag;
/// <summary>
/// トラックの名前。
/// </summary>
public string Name;
private VsqMetaText m_meta_text;
private List<Boare.Lib.Vsq.MidiEvent> 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 );
}
}
}
/// <summary>
/// 歌手変更イベントを曲の先頭から順に返すIteratorを取得します
/// </summary>
/// <returns></returns>
public Iterator getSingerEventIterator() {
return new SingerEventIterator( m_meta_text.getEventList() );
}
/// <summary>
/// 音符イベントを曲の先頭から順に返すIteratorを取得します
/// </summary>
/// <returns></returns>
public Iterator getNoteEventIterator() {
return new NoteEventIterator( m_meta_text.getEventList() );
}
/// <summary>
/// メタテキストを,メモリー上のストリームに出力します
/// </summary>
/// <param name="sw"></param>
/// <param name="encode"></param>
/// <param name="eos"></param>
/// <param name="start"></param>
public void printMetaText( TextMemoryStream sw, int eos, int start ) {
m_meta_text.print( sw, false, eos, start );
}
/// <summary>
/// メタテキストを,指定されたファイルに出力します
/// </summary>
/// <param name="file"></param>
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 );
}
}
}
/// <summary>
/// Masterを取得します
/// </summary>
public VsqMaster getMaster() {
return m_meta_text.master;
}
internal void setMaster( VsqMaster value ) {
m_meta_text.master = value;
}
/// <summary>
/// Mixerを取得します
/// </summary>
public VsqMixer getMixer() {
return m_meta_text.mixer;
}
internal void setMixer( VsqMixer value ) {
m_meta_text.mixer = value;
}
/// <summary>
/// このトラックが保持している指定されたカーブのBPListを取得します
/// </summary>
/// <param name="curve"></param>
/// <returns></returns>
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 );
}
/// <summary>
/// このトラックの,最後に編集が加えられた範囲の,開始位置(クロック)を取得します.
/// このインスタンスを保持しているVsqFileインスタンスのExecuteメソッドによって自動的に更新されます
/// </summary>
public int getEditedStart() {
return m_edited_start;
}
internal void setEditedStart( int value ) {
if ( value < m_edited_start ) {
m_edited_start = value;
}
}
/// <summary>
/// このトラックの,最後に編集が加えられた範囲の,終了位置(クロック)を取得します.
/// このインスタンスを保持しているVsqFileインスタンスのExecuteメソッドによって自動的に更新されます
/// </summary>
public int getEditedEnd() {
return m_edited_end;
}
internal void setEditedEnd( int value ) {
if ( m_edited_end < value ) {
m_edited_end = value;
}
}
/// <summary>
/// このトラックの編集範囲EditedStart, EditedEndをリセットします
/// </summary>
public void resetEditedArea() {
m_edited_start = int.MaxValue;
m_edited_end = int.MinValue;
}
/// <summary>
/// このインスタンスのコピーを作成します
/// </summary>
/// <returns></returns>
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<MidiEvent>( m_midi_event );
}
res.m_edited_start = m_edited_start;
res.m_edited_end = m_edited_end;
res.Renderer = Renderer;
return res;
}
private VsqTrack() {
}
/// <summary>
/// Master Trackを構築
/// </summary>
/// <param name="tempo"></param>
/// <param name="numerator"></param>
/// <param name="denominator"></param>
public VsqTrack( int tempo, int numerator, int denominator ) {
this.Name = "Master Track";
this.m_meta_text = null;
m_midi_event = new List<MidiEvent>();
// テンポを設定
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 );
}
/// <summary>
/// Master Trackでないトラックを構築。
/// </summary>
/// <param name="name"></param>
/// <param name="singer"></param>
public VsqTrack( string name, string singer ) {
Name = name;
m_meta_text = new VsqMetaText( name, singer );
m_midi_event = new List<MidiEvent>();
}
/// <summary>
/// 歌詞の文字数を調べます
/// </summary>
/// <returns></returns>
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<Boare.Lib.Vsq.MidiEvent> midi_events ) {
m_midi_event = new List<MidiEvent>( 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<MidiEvent> getTempoList() {
List<MidiEvent> list = new List<MidiEvent>();
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;
}
/// <summary>
/// MidiEventの中から拍子情報を抽出します
/// </summary>
/// <returns></returns>
public List<MidiEvent> getTimeSigList() {
List<MidiEvent> list = new List<MidiEvent>();
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;
}
}
}