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

179 lines
6.1 KiB
C#

/*
* TempoTableEntry.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;
namespace Boare.Lib.Vsq {
public class TempoTable : ICloneable {
private struct TempoTableEntry : IComparable<TempoTableEntry> {
public int Clock;
public int Tempo;
public double Time;
public TempoTableEntry( int clock, int tempo, double time ) {
Clock = clock;
Tempo = tempo;
Time = time;
}
public int CompareTo( TempoTableEntry item ) {
return Clock - item.Clock;
}
}
private List<TempoTableEntry> m_tempo_table;
private int m_base_tempo;
private int m_tpq;
private TempoTable() {
}
public TempoTable( int base_tempo, int clock_per_quoter ) {
m_base_tempo = base_tempo;
m_tpq = clock_per_quoter;
m_tempo_table = new List<TempoTableEntry>();
m_tempo_table.Add( new TempoTableEntry( 0, base_tempo, 0.0 ) );
}
public object Clone() {
TempoTable ret = new TempoTable();
ret.m_base_tempo = m_base_tempo;
ret.m_tpq = m_tpq;
ret.m_tempo_table = new List<TempoTableEntry>();
for ( int i = 0; i < m_tempo_table.Count; i++ ) {
ret.m_tempo_table.Add( m_tempo_table[i] );
}
ret.update();
return ret;
}
public void add( int clock, int tempo ) {
bool found = false;
for ( int i = 0; i < m_tempo_table.Count; i++ ) {
if ( m_tempo_table[i].Clock == clock ) {
found = true;
m_tempo_table[i] = new TempoTableEntry( clock, tempo, 0.0 );
break;
}
}
if ( !found ) {
m_tempo_table.Add( new TempoTableEntry( clock, tempo, 0.0 ) );
}
m_tempo_table.Sort();
update();
}
public void clear( int base_tempo ) {
m_tempo_table.Clear();
m_tempo_table.Add( new TempoTableEntry( 0, base_tempo, 0.0 ) );
}
private void update() {
for ( int i = 0; i < m_tempo_table.Count; i++ ) {
long sum = 0;
for ( int k = 0; k < i; k++ ) {
sum += (m_tempo_table[k].Tempo * (m_tempo_table[k + 1].Clock - m_tempo_table[k].Clock));
}
double time = sum / (m_tpq * 1e6);
m_tempo_table[i] = new TempoTableEntry( m_tempo_table[i].Clock, m_tempo_table[i].Tempo, time );
}
}
/// <summary>
/// 指定した時刻における、クロックを取得します
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public double getClockFromSec( double time ) {
// timeにおけるテンポを取得
int tempo = m_base_tempo;
double base_clock = 0;
double base_time = 0f;
if ( m_tempo_table.Count == 0 ) {
tempo = m_base_tempo;
base_clock = 0;
base_time = 0f;
} else if ( m_tempo_table.Count == 1 ) {
tempo = m_tempo_table[0].Tempo;
base_clock = m_tempo_table[0].Clock;
base_time = m_tempo_table[0].Time;
} else {
for ( int i = m_tempo_table.Count - 1; i >= 0; i-- ) {
if ( m_tempo_table[i].Time < time ) {
return m_tempo_table[i].Clock + (time - m_tempo_table[i].Time) * m_tpq * 1000000.0 / m_tempo_table[i].Tempo;
}
}
}
double dt = time - base_time;
return base_clock + dt * m_tpq * 1000000.0 / (double)tempo;
}
/// <summary>
/// 指定したクロックにおける、clock=0からの演奏経過時間(sec)を取得します
/// </summary>
/// <param name="clock"></param>
/// <returns></returns>
public double getSecFromClock( int clock ) {
for ( int i = m_tempo_table.Count - 1; i >= 0; i-- ) {
if ( m_tempo_table[i].Clock < clock ) {
double init = m_tempo_table[i].Time;
int dclock = clock - m_tempo_table[i].Clock;
double sec_per_clock1 = m_tempo_table[i].Tempo * 1e-6 / 480.0;
return init + dclock * sec_per_clock1;
}
}
double sec_per_clock = m_base_tempo * 1e-6 / 480.0;
return clock * sec_per_clock;
}
public int getBaseTempo() {
return m_base_tempo;
}
}
[Serializable]
public class TempoTableEntry : IComparable<TempoTableEntry>, ICloneable {
public int Clock;
public int Tempo;
public double Time;
public object Clone() {
return new TempoTableEntry( Clock, Tempo, Time );
}
public TempoTableEntry( int clock, int _tempo, double _time ) {
this.Clock = clock;
this.Tempo = _tempo;
this.Time = _time;
}
public TempoTableEntry() {
}
public int CompareTo( TempoTableEntry entry ) {
return this.Clock - entry.Clock;
}
public bool Equals( TempoTableEntry entry ) {
if ( this.Clock == entry.Clock ) {
return true;
} else {
return false;
}
}
}
}