mirror of
https://git.femboyfinancial.jp/james/lipsync.git
synced 2024-11-26 04:12:00 -08:00
1116 lines
54 KiB
C#
1116 lines
54 KiB
C#
/*
|
|
* SettingsEx.cs
|
|
* Copyright (c) 2007-2009 kbinani
|
|
*
|
|
* This file is part of LipSync.
|
|
*
|
|
* LipSync is free software; you can redistribute it and/or
|
|
* modify it under the terms of the BSD License.
|
|
*
|
|
* LipSync 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.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Drawing.Imaging;
|
|
using System.Runtime.Serialization;
|
|
|
|
using Boare.Lib.AppUtil;
|
|
using Boare.Lib.Vsq;
|
|
|
|
namespace LipSync {
|
|
|
|
public delegate void CommandExecutedEventHandler( TimeTableType command_target, CommandType command_type );
|
|
|
|
[Serializable]
|
|
public class SettingsEx : IDisposable, ICloneable {
|
|
const double tpq_sec = 480000000.0;
|
|
|
|
public TimeTableGroup m_group_vsq; //ok
|
|
public List<TimeTableGroup> m_groups_character; //ok
|
|
public TimeTableGroup m_group_another; //ok
|
|
public TimeTableGroup m_group_plugin; //ok
|
|
public int m_screenWidth = 512; //ok
|
|
public int m_screenHeight = 384; //ok
|
|
public float m_totalSec = 0.0f; //ok
|
|
public Size m_movieSize; // = new Size( 512, 384 ); //ok
|
|
public List<PluginConfig> m_plugins_config; //ok
|
|
public string m_audioFile = ""; //ok
|
|
[OptionalField]
|
|
public Color CANVAS_BACKGROUND; // = Color.White; //ok
|
|
[OptionalField]
|
|
public float REPEAT_START; //ok
|
|
[OptionalField]
|
|
public float REPEAT_END; //ok
|
|
[OptionalField]
|
|
public List<TimeSigTableEntry> m_timesig_ex;
|
|
[OptionalField]
|
|
public List<TempoTableEntry> m_tempo;
|
|
[OptionalField]
|
|
public int m_base_tempo;
|
|
[OptionalField]
|
|
public uint m_dwRate = 30;
|
|
[OptionalField]
|
|
public uint m_dwScale = 1;
|
|
[NonSerialized]
|
|
private float m_fps_buffer = 30f;
|
|
[NonSerialized]
|
|
public PluginInfo[] m_plugins;
|
|
[OptionalField]
|
|
public List<Telop> m_telop_ex2 = new List<Telop>();
|
|
[OptionalField]
|
|
public bool TelopListFolded = false;
|
|
/// <summary>
|
|
/// 描画順序で格納された描画物のリスト
|
|
/// </summary>
|
|
[NonSerialized]
|
|
public List<ZorderItem> m_zorder = new List<ZorderItem>();
|
|
[OptionalField]
|
|
public string VersionMarker = AppManager.VERSION;// "2.4.4";
|
|
|
|
public static event CommandExecutedEventHandler CommandExecuted;
|
|
|
|
private static string _( string s ) {
|
|
return Messaging.GetMessage( s );
|
|
}
|
|
|
|
public void DrawTo( Graphics g, Size mSize, float now, bool is_transparent ) {
|
|
DrawTo( g, mSize, now, is_transparent, "", 0 );
|
|
}
|
|
|
|
public void DrawTo( Graphics g, Size mSize, float now, bool is_transparent, string mouth, int mouth_force_group_index ) {
|
|
if ( mouth.Length == 0 ) {
|
|
mouth_force_group_index = -1;
|
|
}
|
|
#if DEBUG
|
|
//Common.DebugWriteLine( "SettingsEx+DrawTo(Graphics,Size,float,bool)" );
|
|
int chrpos = 10;
|
|
#endif
|
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
|
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
|
|
if ( is_transparent ) {
|
|
g.Clear( Color.Transparent );
|
|
} else {
|
|
g.Clear( CANVAS_BACKGROUND );
|
|
}
|
|
|
|
ColorMatrix cm = new ColorMatrix();
|
|
cm.Matrix00 = 1;
|
|
cm.Matrix11 = 1;
|
|
cm.Matrix22 = 1;
|
|
cm.Matrix33 = 1f;
|
|
cm.Matrix44 = 1;
|
|
|
|
for ( int z = 0; z < m_zorder.Count; z++ ) {
|
|
ZorderItemType type = m_zorder[z].Type;
|
|
int index = m_zorder[z].Index;
|
|
|
|
Bitmap tmp = null;
|
|
PointF position = new PointF();
|
|
float scale = 1f;
|
|
float alpha = 1f;
|
|
float rotate = 0f;
|
|
Size size = new Size();
|
|
|
|
if ( type == ZorderItemType.another ) {
|
|
if ( !m_group_another[index].IsAviMode ) {
|
|
if ( m_group_another[index].Image == null ) {
|
|
continue;
|
|
}
|
|
int start_entry = m_group_another[index].Value;
|
|
for ( int entry = start_entry; entry < m_group_another[index].Count; entry++ ) {
|
|
if ( m_group_another[index][entry].begin <= now && now <= m_group_another[index][entry].end ) {
|
|
m_group_another[index].Value = entry;
|
|
tmp = m_group_another[index].Image;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
tmp = m_group_another[index].GetImage( now );
|
|
}
|
|
position = m_group_another[index].GetPosition( now );
|
|
size = m_group_another[index].ImageSize;
|
|
scale = m_group_another[index].GetScale( now );
|
|
alpha = m_group_another[index].GetAlpha( now );
|
|
rotate = m_group_another[index].GetRotate( now );
|
|
} else if ( type == ZorderItemType.character ) {
|
|
if ( m_groups_character[index].Character.Type == CharacterType.def ) {
|
|
int[] draw;
|
|
if ( mouth_force_group_index == index ) {
|
|
draw = m_groups_character[index].GetDrawObjectIndex( now, mouth );
|
|
} else {
|
|
draw = m_groups_character[index].GetDrawObjectIndex( now, "" );
|
|
}
|
|
position = m_groups_character[index].GetPosition( now );
|
|
size = m_groups_character[index].Character.Size;
|
|
scale = m_groups_character[index].GetScale( now );
|
|
float tscale = Math.Abs( scale );
|
|
if ( tscale == 0.0f ) {
|
|
continue;
|
|
}
|
|
alpha = m_groups_character[index].GetAlpha( now );
|
|
if ( alpha <= 0.0f ) {
|
|
continue;
|
|
}
|
|
rotate = m_groups_character[index].GetRotate( now );
|
|
#if DEBUG
|
|
chrpos += 10;
|
|
g.DrawString( "character: position=" + position + ", m_groups_character[group].Position=" + m_groups_character[index].Position, AppManager.Config.Font.GetFont(), Brushes.Black, new PointF( 0, chrpos ) );
|
|
#endif
|
|
tmp = m_groups_character[index].Character.Face( draw );
|
|
} else {
|
|
string[] draw = m_groups_character[index].GetDrawObjectNames( now );
|
|
int target_plugin = -1;
|
|
for ( int i = 0; i < m_plugins_config.Count; i++ ) {
|
|
if ( m_plugins_config[i].ID == m_groups_character[index].Character.PluginConfig.ID ) {
|
|
target_plugin = i;
|
|
break;
|
|
}
|
|
}
|
|
if ( target_plugin >= 0 ) {
|
|
string s = "";
|
|
bool first = true;
|
|
for ( int i = 0; i < draw.Length; i++ ) {
|
|
if ( first ) {
|
|
s += draw[i];
|
|
first = false;
|
|
} else {
|
|
s += "\n" + draw[i];
|
|
}
|
|
}
|
|
m_plugins[target_plugin].Instance.Render( g, mSize, now, s, "" );
|
|
}
|
|
continue;
|
|
}
|
|
} else if ( type == ZorderItemType.plugin ) {
|
|
int start_entry = m_group_plugin[index].Value;
|
|
for ( int entry = start_entry; entry < m_group_plugin[index].Count; entry++ ) {
|
|
if ( m_group_plugin[index][entry].begin <= now && now <= m_group_plugin[index][entry].end ) {
|
|
m_group_plugin[index].Value = entry;
|
|
#if DEBUG
|
|
chrpos += 10;
|
|
g.DrawString( "plugin", AppManager.Config.Font.GetFont(), Brushes.Black, new PointF( 0, chrpos ) );
|
|
#endif
|
|
tmp = new Bitmap( mSize.Width, mSize.Height );
|
|
TimeTableEntry tmptt = m_group_plugin[index][entry];
|
|
m_plugins[index].Instance.Apply( ref tmp, now, tmptt.begin, tmptt.end, ref tmptt.body );
|
|
m_group_plugin[index][entry] = tmptt;
|
|
size = mSize;
|
|
position = new PointF( 0f, 0f );
|
|
alpha = 1f;
|
|
scale = 1f;
|
|
rotate = 0f;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
if ( tmp != null ) {
|
|
float tscale = Math.Abs( scale );
|
|
if ( scale < 0 ) {
|
|
tmp.RotateFlip( RotateFlipType.RotateNoneFlipX );
|
|
}
|
|
if ( scale != 0.0f ) {
|
|
g.ResetTransform();
|
|
float half_width = size.Width / 2f;
|
|
float half_height = size.Height / 2f;
|
|
g.TranslateTransform( position.X + half_width * tscale, position.Y + half_height * tscale );
|
|
if ( scale != 1f ) {
|
|
g.ScaleTransform( tscale, tscale );
|
|
}
|
|
InterpolationMode im = g.InterpolationMode;
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
if ( scale == 1f && rotate == 0f ) {
|
|
g.InterpolationMode = InterpolationMode.Default;
|
|
g.SmoothingMode = SmoothingMode.Default;
|
|
}
|
|
if ( rotate != 0f ) {
|
|
g.RotateTransform( rotate );
|
|
}
|
|
if ( 0 < alpha && alpha < 1f ) {
|
|
cm.Matrix33 = alpha;
|
|
ImageAttributes ia = new ImageAttributes();
|
|
ia.SetColorMatrix( cm );
|
|
g.DrawImage( tmp,
|
|
new PointF[]{ new PointF( -half_width, - half_height ),
|
|
new PointF( half_width, -half_height ),
|
|
new PointF( -half_width, half_height ) },
|
|
new RectangleF( 0f, 0f, size.Width, size.Height ),
|
|
GraphicsUnit.Pixel,
|
|
ia );
|
|
} else if ( alpha != 0f ) {
|
|
g.DrawImage( tmp, -half_width, -half_height, (float)size.Width, (float)size.Height );
|
|
}
|
|
g.InterpolationMode = im;
|
|
g.SmoothingMode = sm;
|
|
g.ResetTransform();
|
|
}
|
|
}
|
|
}
|
|
|
|
//最後に字幕を入れる
|
|
foreach ( Telop telop in m_telop_ex2 ) {
|
|
if ( telop.Start <= now && now <= telop.End ) {
|
|
float alpha = 1f;
|
|
if ( telop.FadeIn ) {
|
|
float diff = now - telop.Start;
|
|
if ( 0f <= diff && diff <= telop.FadeInSpan ) {
|
|
alpha = 1.0f / telop.FadeInSpan * diff;
|
|
}
|
|
}
|
|
if ( telop.FadeOut ) {
|
|
float diff = telop.End - now;
|
|
if ( 0f <= diff && diff <= telop.FadeOutSpan ) {
|
|
alpha = 1.0f / telop.FadeOutSpan * diff;
|
|
}
|
|
}
|
|
PointF position = telop.GetPosition( now );
|
|
Size size = telop.ImageSize;
|
|
float scale = telop.GetScale( now );
|
|
float talpha = telop.GetAlpha( now );
|
|
float rotate = telop.GetRotate( now );
|
|
g.ResetTransform();
|
|
if ( scale != 0.0f ) {
|
|
g.TranslateTransform( position.X + size.Width / 2f * scale, position.Y + size.Height / 2f * scale );
|
|
if ( scale != 1f ) {
|
|
g.ScaleTransform( scale, scale );
|
|
}
|
|
if ( rotate != 0f ) {
|
|
g.RotateTransform( rotate );
|
|
}
|
|
g.DrawString( telop.Text,
|
|
telop.Font,
|
|
new SolidBrush( Color.FromArgb( (int)(talpha * alpha * 255), telop.Color ) ),
|
|
(int)(-size.Width / 2),
|
|
(int)(-size.Height / 2) );
|
|
g.ResetTransform();
|
|
}
|
|
}
|
|
}
|
|
//}
|
|
//return bmp;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Settingsからのコンバート
|
|
/// </summary>
|
|
/// <param name="s"></param>
|
|
public SettingsEx( Settings s ) {
|
|
#if DEBUG
|
|
Common.DebugWriteLine( "SettingsEx..ctor(Settings)" );
|
|
#endif
|
|
m_group_vsq = (TimeTableGroup)s.m_group_vsq.Clone();
|
|
m_groups_character = new List<TimeTableGroup>();
|
|
for( int i = 0; i < s.m_groups_character.Count; i++ ){
|
|
m_groups_character.Add( (TimeTableGroup)s.m_groups_character[i].Clone() );
|
|
}
|
|
m_group_another = (TimeTableGroup)s.m_group_another.Clone();
|
|
m_group_plugin = (TimeTableGroup)s.m_group_plugin.Clone();
|
|
m_screenWidth = s.m_screenWidth;
|
|
m_screenHeight = s.m_screenHeight;
|
|
m_totalSec = s.m_totalSec;
|
|
m_movieSize = s.m_movieSize;
|
|
m_plugins_config = new List<PluginConfig>();
|
|
for( int i = 0; i < s.m_plugins_config.Count; i++ ){
|
|
m_plugins_config.Add( s.m_plugins_config[i].Clone() );
|
|
}
|
|
m_audioFile = s.m_audioFile;
|
|
CANVAS_BACKGROUND = s.CANVAS_BACKGROUND;
|
|
REPEAT_START = s.REPEAT_START;
|
|
REPEAT_END = s.REPEAT_START;
|
|
m_timesig_ex = new List<TimeSigTableEntry>();
|
|
for( int i = 0; i < s.m_timesig_ex.Count; i++ ){
|
|
if ( s.m_timesig_ex[i].Numerator == 0 || s.m_timesig_ex[i].Denominator == 0 ) {
|
|
m_timesig_ex.Clear();
|
|
break;
|
|
}
|
|
m_timesig_ex.Add( (TimeSigTableEntry)s.m_timesig_ex[i].Clone() );
|
|
}
|
|
m_tempo = new List<TempoTableEntry>();
|
|
for( int i = 0; i < s.m_tempo.Count; i++ ){
|
|
m_tempo.Add( (TempoTableEntry)s.m_tempo[i].Clone() );
|
|
}
|
|
m_base_tempo = s.m_base_tempo;
|
|
m_dwRate = s.m_dwRate;
|
|
m_dwScale = s.m_dwScale;
|
|
m_fps_buffer = m_dwRate / (float)m_dwScale;
|
|
m_telop_ex2 = new List<Telop>();
|
|
for ( int i = 0; i < s.m_telop_ex2.Count; i++ ) {
|
|
m_telop_ex2.Add( (Telop)s.m_telop_ex2[i].Clone() );
|
|
}
|
|
}
|
|
|
|
public Telop this[int id] {
|
|
get {
|
|
foreach ( Telop item in m_telop_ex2 ) {
|
|
if ( item.ID == id ) {
|
|
return item;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
set {
|
|
for ( int i = 0; i < m_telop_ex2.Count; i++ ) {
|
|
if ( m_telop_ex2[i].ID == id ) {
|
|
m_telop_ex2[i] = value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public float FrameRate {
|
|
get {
|
|
return m_fps_buffer;
|
|
}
|
|
}
|
|
|
|
public uint DwRate {
|
|
get {
|
|
return m_dwRate;
|
|
}
|
|
set {
|
|
m_dwRate = value;
|
|
m_fps_buffer = (float)m_dwRate / (float)m_dwScale;
|
|
}
|
|
}
|
|
|
|
public uint DwScale {
|
|
get {
|
|
return m_dwScale;
|
|
}
|
|
set {
|
|
m_dwScale = value;
|
|
m_fps_buffer = (float)m_dwRate / (float)m_dwScale;
|
|
}
|
|
}
|
|
|
|
public object Clone() {
|
|
SettingsEx res = new SettingsEx();
|
|
res.m_group_vsq = (TimeTableGroup)m_group_vsq.Clone();
|
|
res.m_groups_character = new List<TimeTableGroup>();
|
|
for ( int i = 0; i < m_groups_character.Count; i++ ) {
|
|
res.m_groups_character.Add( (TimeTableGroup)m_groups_character[i].Clone() );
|
|
}
|
|
res.m_group_another = (TimeTableGroup)m_group_another.Clone();
|
|
res.m_group_plugin = (TimeTableGroup)m_group_plugin.Clone();
|
|
//res.fps = fps;
|
|
res.m_screenWidth = m_screenWidth;
|
|
res.m_screenHeight = m_screenHeight;
|
|
res.m_totalSec = m_totalSec;
|
|
res.m_movieSize = m_movieSize;
|
|
res.m_plugins_config = new List<PluginConfig>();
|
|
for ( int i = 0; i < m_plugins_config.Count; i++ ) {
|
|
res.m_plugins_config.Add( m_plugins_config[i].Clone() );
|
|
}
|
|
res.m_audioFile = m_audioFile;
|
|
res.CANVAS_BACKGROUND = CANVAS_BACKGROUND;
|
|
res.REPEAT_START = REPEAT_START;
|
|
res.REPEAT_END = REPEAT_END;
|
|
res.m_telop_ex2 = new List<Telop>();
|
|
foreach ( Telop item in m_telop_ex2 ) {
|
|
res.m_telop_ex2.Add( (Telop)item.Clone() );
|
|
}
|
|
res.m_timesig_ex = new List<TimeSigTableEntry>();
|
|
for ( int i = 0; i < m_timesig_ex.Count; i++ ) {
|
|
res.m_timesig_ex.Add( (TimeSigTableEntry)m_timesig_ex[i].Clone() );
|
|
}
|
|
res.m_tempo = new List<TempoTableEntry>();
|
|
for ( int i = 0; i < m_tempo.Count; i++ ) {
|
|
res.m_tempo.Add( (TempoTableEntry)m_tempo[i].Clone() );
|
|
}
|
|
res.m_base_tempo = m_base_tempo;
|
|
res.m_zorder = new List<ZorderItem>();
|
|
for ( int i = 0; i < m_zorder.Count; i++ ) {
|
|
res.m_zorder.Add( (ZorderItem)m_zorder[i].Clone() );
|
|
}
|
|
/*res.m_commands = new List<Command>();
|
|
for ( int i = 0; i < m_commands.Count; i++ ) {
|
|
res.m_commands.Add( m_commands[i].Clone() );
|
|
}
|
|
res.m_command_position = m_command_position;*/
|
|
res.DwRate = m_dwRate;
|
|
res.DwScale = m_dwScale;
|
|
return res;
|
|
}
|
|
|
|
|
|
public TimeTableGroup this[TimeTableType type, int group] {
|
|
get {
|
|
if ( type == TimeTableType.character ) {
|
|
return m_groups_character[group];
|
|
} else {
|
|
switch ( type ) {
|
|
case TimeTableType.another:
|
|
return m_group_another;
|
|
case TimeTableType.plugin:
|
|
return m_group_plugin;
|
|
case TimeTableType.vsq:
|
|
return m_group_vsq;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
set {
|
|
if ( type == TimeTableType.character ) {
|
|
m_groups_character[group] = value;
|
|
} else {
|
|
switch ( type ) {
|
|
case TimeTableType.another:
|
|
m_group_another = value;
|
|
break;
|
|
case TimeTableType.plugin:
|
|
m_group_plugin = value;
|
|
break;
|
|
case TimeTableType.vsq:
|
|
m_group_vsq = value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public SettingsEx() {
|
|
m_zorder = new List<ZorderItem>();
|
|
m_group_vsq = new TimeTableGroup( _( "VSQ Tracks" ), -1, null );
|
|
m_groups_character = new List<TimeTableGroup>();
|
|
m_group_another = new TimeTableGroup( _( "Another images" ), -1, null );
|
|
m_group_plugin = new TimeTableGroup( _( "Plugin" ), -1, null );
|
|
m_telop_ex2 = new List<Telop>();
|
|
m_screenWidth = 512;
|
|
m_screenHeight = 384;
|
|
m_totalSec = 0.0f;
|
|
m_movieSize = new Size( 512, 384 );
|
|
m_plugins_config = new List<PluginConfig>();
|
|
m_audioFile = "";
|
|
CANVAS_BACKGROUND = Color.White;
|
|
m_telop_ex2 = new List<Telop>();
|
|
m_timesig_ex = new List<TimeSigTableEntry>();
|
|
m_tempo = new List<TempoTableEntry>();
|
|
m_base_tempo = 480000;
|
|
m_dwRate = 30;
|
|
m_dwScale = 1;
|
|
m_fps_buffer = (float)m_dwRate / (float)m_dwScale;
|
|
}
|
|
|
|
[OnDeserializing]
|
|
private void onDeserializing( StreamingContext sc ) {
|
|
CANVAS_BACKGROUND = Color.White;
|
|
m_telop_ex2 = new List<Telop>();
|
|
REPEAT_START = 0f;
|
|
REPEAT_END = -1f;
|
|
m_dwRate = 0;
|
|
m_dwScale = 0;
|
|
}
|
|
|
|
[OnDeserialized]
|
|
private void onDeserialized( StreamingContext sc ) {
|
|
#if DEBUG
|
|
Common.DebugWriteLine( "SettingsEx.onDeserialized(StreamingContext)" );
|
|
Common.DebugWriteLine( " m_timesig_ex" );
|
|
#endif
|
|
m_zorder = new List<ZorderItem>();
|
|
if ( m_timesig_ex == null ) {
|
|
m_timesig_ex = new List<TimeSigTableEntry>();
|
|
} else {
|
|
for ( int i = 0; i < m_timesig_ex.Count; i++ ) {
|
|
#if DEBUG
|
|
Common.DebugWriteLine( " " + m_timesig_ex[i].ToString() );
|
|
#endif
|
|
if ( m_timesig_ex[i].Numerator == 0 || m_timesig_ex[i].Denominator == 0 ) {
|
|
m_timesig_ex.Clear();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if( m_tempo == null ) {
|
|
m_tempo = new List<TempoTableEntry>();
|
|
}
|
|
if ( m_dwRate == 0 ) {
|
|
m_dwScale = 1;
|
|
m_dwRate = 30;
|
|
}
|
|
m_fps_buffer = (float)m_dwRate / (float)m_dwScale;
|
|
#if DEBUG
|
|
Common.DebugWriteLine( " m_telop_ex2" );
|
|
for ( int i = 0; i < m_telop_ex2.Count; i++ ) {
|
|
Common.DebugWriteLine( " i=" + i + "; ID=" + m_telop_ex2[i].ID + "; Text=" + m_telop_ex2[i].Text );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
public void Dispose() {
|
|
if ( m_group_vsq != null ) {
|
|
m_group_vsq.Dispose();
|
|
m_group_vsq = null;
|
|
}
|
|
if ( m_groups_character != null ) {
|
|
m_groups_character.Clear();
|
|
m_groups_character = null;
|
|
}
|
|
if ( m_group_another != null ) {
|
|
m_group_another.Dispose();
|
|
m_group_another = null;
|
|
}
|
|
if ( m_group_plugin != null ) {
|
|
m_group_plugin.Dispose();
|
|
m_group_plugin = null;
|
|
}
|
|
if ( m_plugins_config != null ) {
|
|
m_plugins_config.Clear();
|
|
m_plugins_config = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// m_telop_ex用。次に利用可能なIDを調べます
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public int GetNextID() {
|
|
return GetNextID( 0 );
|
|
}
|
|
|
|
public int GetNextID( int skip ) {
|
|
int draft = -1;
|
|
while ( true ) {
|
|
draft++;
|
|
bool found = false;
|
|
foreach ( Telop item in m_telop_ex2 ) {
|
|
if ( draft == item.ID ) {
|
|
found = true;
|
|
}
|
|
}
|
|
if ( !found ) {
|
|
break;
|
|
}
|
|
}
|
|
return draft + skip;
|
|
}
|
|
|
|
public void SetZorder( ZorderItem item, int zorder ) {
|
|
switch ( item.Type ) {
|
|
case ZorderItemType.plugin:
|
|
m_group_plugin[item.Index].ZOrder = zorder;
|
|
break;
|
|
case ZorderItemType.another:
|
|
m_group_another[item.Index].ZOrder = zorder;
|
|
break;
|
|
case ZorderItemType.character:
|
|
m_groups_character[item.Index].ZOrder = zorder;
|
|
break;
|
|
}
|
|
}
|
|
|
|
public int GetZorder( ZorderItem item ) {
|
|
switch ( item.Type ) {
|
|
case ZorderItemType.plugin:
|
|
return m_group_plugin[item.Index].ZOrder;
|
|
case ZorderItemType.another:
|
|
return m_group_another[item.Index].ZOrder;
|
|
case ZorderItemType.character:
|
|
return m_groups_character[item.Index].ZOrder;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public void UpdateZorder() {
|
|
m_zorder.Clear();
|
|
for ( int i = 0; i < m_plugins_config.Count; i++ ) {
|
|
m_zorder.Add( new ZorderItem( m_plugins_config[i].ID, ZorderItemType.plugin, i ) );
|
|
}
|
|
for ( int i = 0; i < m_groups_character.Count; i++ ) {
|
|
m_zorder.Add( new ZorderItem( m_groups_character[i].Text, ZorderItemType.character, i ) );
|
|
}
|
|
for ( int i = 0; i < m_group_another.Count; i++ ) {
|
|
m_zorder.Add( new ZorderItem( m_group_another[i].Text, ZorderItemType.another, i ) );
|
|
}
|
|
|
|
bool changed = true;
|
|
ZorderItem tmp;
|
|
while ( changed ) {
|
|
changed = false;
|
|
for ( int i = 0; i < m_zorder.Count - 1; i++ ) {
|
|
int order_i = GetZorder( m_zorder[i] );
|
|
int order_ipp = GetZorder( m_zorder[i + 1] );
|
|
if ( order_i < order_ipp || (order_i == order_ipp && m_zorder[i + 1].Type.CompareTo( m_zorder[i].Type ) > 0) ) {
|
|
tmp = (ZorderItem)m_zorder[i].Clone();
|
|
m_zorder[i] = (ZorderItem)m_zorder[i + 1].Clone();
|
|
m_zorder[i + 1] = (ZorderItem)tmp.Clone();
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( int i = 0; i < m_zorder.Count; i++ ) {
|
|
SetZorder( m_zorder[i], m_zorder.Count - 1 - i );
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 指定されたコマンドを実行します
|
|
/// </summary>
|
|
/// <param name="command"></param>
|
|
public Command Execute( Command command ) {
|
|
int group = command.group;
|
|
int track = command.track;
|
|
int entry = command.entry;
|
|
TimeTableType target = command.target;
|
|
|
|
Command ret = null;
|
|
switch ( command.target ) {
|
|
case TimeTableType.telop:
|
|
#region telop
|
|
switch ( command.type ) {
|
|
case CommandType.addTelop:
|
|
Telop adding = (Telop)command.telop.Clone( GetNextID() );
|
|
ret = Command.GCommandDeleteTelop( adding );
|
|
m_telop_ex2.Add( adding );
|
|
break;
|
|
case CommandType.editTelop:
|
|
ret = Command.GCommandEditTelop( command.telop.ID, this[command.telop.ID] );
|
|
this[command.telop.ID] = (Telop)command.telop.Clone();
|
|
break;
|
|
case CommandType.deleteTelop:
|
|
ret = Command.GCommandAddTelop( this[command.telop.ID] );
|
|
for ( int i = 0; i < m_telop_ex2.Count; i++ ) {
|
|
if ( m_telop_ex2[i].ID == command.telop.ID ) {
|
|
m_telop_ex2.RemoveAt( i );
|
|
break;
|
|
}
|
|
}
|
|
Property.Instance.Editing = null; //dirty...
|
|
break;
|
|
case CommandType.shiftTimeTable:
|
|
ret = Command.GCommandShiftTimeTable( target, -1, -command.floatValue );
|
|
for ( int i = 0; i < m_telop_ex2.Count; i++ ) {
|
|
m_telop_ex2[i].Start += command.floatValue;
|
|
m_telop_ex2[i].End += command.floatValue;
|
|
}
|
|
break;
|
|
case CommandType.addTelopRange:
|
|
Telop[] adding2 = (Telop[])command.args[0];
|
|
for ( int i = 0; i < adding2.Length; i++ ) {
|
|
adding2[i] = (Telop)adding2[i].Clone( GetNextID( i ) );
|
|
}
|
|
ret = Command.GCommandDeleteTelopRange( adding2 );
|
|
m_telop_ex2.AddRange( adding2 );
|
|
break;
|
|
case CommandType.deleteTelopRange:
|
|
Telop[] adding3 = (Telop[])command.args[0];
|
|
ret = Command.GCommandAddTelopRange( adding3 );
|
|
for ( int i = 0; i < adding3.Length; i++ ) {
|
|
for ( int j = 0; j < m_telop_ex2.Count; j++ ) {
|
|
if ( m_telop_ex2[j].ID == adding3[i].ID ) {
|
|
m_telop_ex2.RemoveAt( j );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
Telop.DecideLane( m_telop_ex2 );
|
|
#endregion
|
|
break;
|
|
case TimeTableType.another:
|
|
#region another
|
|
switch ( command.type ) {
|
|
case CommandType.addEntry:
|
|
ret = Command.GCommandDeleteTimeTableEntry( target, -1, track, command.item );
|
|
m_group_another[track].Add( (TimeTableEntry)command.item.Clone() );
|
|
m_group_another[track].Sort();
|
|
break;
|
|
case CommandType.deleteEntry:
|
|
ret = Command.GCommandAddTimeTableEntry( target, -1, track, command.item );
|
|
m_group_another[track].Remove( command.item );
|
|
break;
|
|
case CommandType.editEntry:
|
|
ret = Command.GCommandEditTimeTableEntry( target, -1, track, entry, m_group_another[track][entry] );
|
|
m_group_another[track][entry] = (TimeTableEntry)command.item.Clone();
|
|
break;
|
|
case CommandType.addTimeTable:
|
|
ret = Command.GCommandDeleteTimeTable( target, -1, m_group_another.Count );
|
|
m_group_another.Insert( command.track, (TimeTable)command.table.Clone() );
|
|
UpdateZorder();
|
|
break;
|
|
case CommandType.deleteTimeTable:
|
|
ret = Command.GCommandAddTimeTable( target, -1, track, m_group_another[track] );
|
|
m_group_another.RemoveAt( command.track );
|
|
UpdateZorder();
|
|
break;
|
|
case CommandType.editTimeTable:
|
|
ret = Command.GCommandEditTimeTable( target, -1, track, m_group_another[track] );
|
|
m_group_another[command.track].Clear();
|
|
m_group_another[command.track] = (TimeTable)command.table.Clone();
|
|
break;
|
|
case CommandType.setImage:
|
|
if ( m_group_another[track].IsAviMode ) {
|
|
ret = Command.GCommandSetAvi( track, m_group_another[track].AviConfig );
|
|
} else {
|
|
ret = Command.GCommandSetImage( track, m_group_another[track].Image );
|
|
}
|
|
m_group_another[command.track].SetImage( command.image );
|
|
break;
|
|
case CommandType.setPosition:
|
|
ret = Command.GCommandSetPosition( target, -1, track, m_group_another[track].Position );
|
|
m_group_another[command.track].Position = command.position;
|
|
break;
|
|
case CommandType.changeScale:
|
|
ret = Command.GCommandChangeScale( target, -1, track, m_group_another[track].Scale );
|
|
m_group_another[command.track].Scale = command.floatValue;
|
|
break;
|
|
case CommandType.editGroup:
|
|
ret = Command.GCommandEditGroup( target, -1, m_group_another );
|
|
m_group_another = null;
|
|
m_group_another = (TimeTableGroup)command.tablegroup.Clone();
|
|
break;
|
|
case CommandType.setAvi:
|
|
if ( m_group_another[track].IsAviMode ) {
|
|
ret = Command.GCommandSetAvi( track, m_group_another[track].AviConfig );
|
|
} else {
|
|
ret = Command.GCommandSetImage( track, m_group_another[track].Image );
|
|
}
|
|
m_group_another[command.track].SetAvi( command.str );
|
|
break;
|
|
case CommandType.shiftTimeTable:
|
|
ret = Command.GCommandShiftTimeTable( target, track, -command.floatValue );
|
|
for ( int i = 0; i < m_group_another[track].Count; i++ ) {
|
|
m_group_another[track][i].begin += command.floatValue;
|
|
m_group_another[track][i].end += command.floatValue;
|
|
}
|
|
break;
|
|
}
|
|
#endregion
|
|
break;
|
|
case TimeTableType.character:
|
|
#region character
|
|
switch ( command.type ) {
|
|
case CommandType.addEntry:
|
|
ret = Command.GCommandDeleteTimeTableEntry( target, group, track, command.item );
|
|
m_groups_character[group][track].Add( (TimeTableEntry)command.item.Clone() );
|
|
m_groups_character[group][track].Sort();
|
|
break;
|
|
case CommandType.deleteEntry:
|
|
ret = Command.GCommandAddTimeTableEntry( target, group, track, command.item );
|
|
m_groups_character[group][track].Remove( command.item );
|
|
break;
|
|
case CommandType.editEntry:
|
|
ret = Command.GCommandEditTimeTableEntry( target, group, track, entry, m_groups_character[group][track][entry] );
|
|
m_groups_character[group][track][entry] = (TimeTableEntry)command.item.Clone();
|
|
break;
|
|
case CommandType.addTimeTable:
|
|
ret = Command.GCommandDeleteTimeTable( target, group, m_groups_character[group].Count );
|
|
m_groups_character[group].Insert( command.track, (TimeTable)command.table.Clone() );
|
|
UpdateZorder();
|
|
break;
|
|
case CommandType.deleteTimeTable:
|
|
ret = Command.GCommandAddTimeTable( target, group, track, m_groups_character[group][track] );
|
|
m_groups_character[group].RemoveAt( command.track );
|
|
UpdateZorder();
|
|
break;
|
|
case CommandType.editTimeTable:
|
|
ret = Command.GCommandEditTimeTable( target, group, track, m_groups_character[group][track] );
|
|
m_groups_character[command.group][command.track].Clear();
|
|
m_groups_character[command.group][command.track] = (TimeTable)command.table.Clone();
|
|
break;
|
|
case CommandType.addGroup:
|
|
ret = Command.GCommandDeleteTimeTableGroup( target, m_groups_character.Count );
|
|
m_groups_character.Insert( command.group, (TimeTableGroup)command.tablegroup.Clone() );
|
|
UpdateZorder();
|
|
break;
|
|
case CommandType.deleteGroup:
|
|
ret = Command.GCommandAddGroup( target, group, m_groups_character[group] );
|
|
m_groups_character.RemoveAt( command.group );
|
|
Property.Instance.Editing = null;
|
|
UpdateZorder();
|
|
break;
|
|
case CommandType.editGroup:
|
|
ret = Command.GCommandEditGroup( target, group, m_groups_character[group] );
|
|
m_groups_character[command.group].Dispose();
|
|
m_groups_character[command.group] = (TimeTableGroup)command.tablegroup.Clone();
|
|
break;
|
|
case CommandType.setPosition:
|
|
ret = Command.GCommandSetPosition( target, group, track, m_groups_character[group].Position );
|
|
m_groups_character[command.group].Position = command.position;
|
|
break;
|
|
case CommandType.changeScale:
|
|
ret = Command.GCommandChangeScale( target, group, -1, m_groups_character[group].Scale );
|
|
m_groups_character[command.group].Scale = command.floatValue;
|
|
break;
|
|
case CommandType.shiftTimeTable:
|
|
ret = Command.GCommandShiftTimeTable( target, group, -command.floatValue );
|
|
for ( int i = 0; i < m_groups_character[group].Count; i++ ) {
|
|
for ( int j = 0; j < m_groups_character[group][i].Count; j++ ) {
|
|
m_groups_character[group][i][j].begin += command.floatValue;
|
|
m_groups_character[group][i][j].end += command.floatValue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#endregion
|
|
break;
|
|
case TimeTableType.plugin:
|
|
#region plugin
|
|
switch ( command.type ) {
|
|
case CommandType.addEntry:
|
|
ret = Command.GCommandDeleteTimeTableEntry( target, -1, track, command.item );
|
|
m_group_plugin[track].Add( (TimeTableEntry)command.item.Clone() );
|
|
m_group_plugin[track].Sort();
|
|
break;
|
|
case CommandType.deleteEntry:
|
|
ret = Command.GCommandAddTimeTableEntry( target, -1, track, command.item );
|
|
m_group_plugin[track].Remove( command.item );
|
|
break;
|
|
case CommandType.editEntry:
|
|
ret = Command.GCommandEditTimeTableEntry( target, -1, track, entry, m_group_plugin[track][entry] );
|
|
m_group_plugin[track][entry] = (TimeTableEntry)command.item.Clone();
|
|
break;
|
|
case CommandType.addTimeTable:
|
|
ret = Command.GCommandDeleteTimeTable( target, -1, m_group_plugin.Count );
|
|
m_group_plugin.Insert( command.track, (TimeTable)command.table.Clone() );
|
|
UpdateZorder();
|
|
break;
|
|
case CommandType.deleteTimeTable:
|
|
ret = Command.GCommandAddTimeTable( target, -1, track, m_group_plugin[track] );
|
|
m_group_plugin.RemoveAt( command.track );
|
|
UpdateZorder();
|
|
break;
|
|
case CommandType.editTimeTable:
|
|
ret = Command.GCommandEditTimeTable( target, -1, track, m_group_plugin[track] );
|
|
m_group_plugin[command.track].Clear();
|
|
m_group_plugin[command.track] = (TimeTable)command.table.Clone();
|
|
break;
|
|
case CommandType.editGroup:
|
|
ret = Command.GCommandEditGroup( target, -1, m_group_plugin );
|
|
m_group_plugin = null;
|
|
m_group_plugin = (TimeTableGroup)command.tablegroup.Clone();
|
|
break;
|
|
case CommandType.shiftTimeTable:
|
|
ret = Command.GCommandShiftTimeTable( target, track, -command.floatValue );
|
|
for ( int i = 0; i < m_group_plugin[track].Count; i++ ) {
|
|
m_group_plugin[track][i].begin += command.floatValue;
|
|
m_group_plugin[track][i].end += command.floatValue;
|
|
}
|
|
break;
|
|
}
|
|
#endregion
|
|
break;
|
|
case TimeTableType.vsq:
|
|
#region vsq
|
|
switch ( command.type ) {
|
|
case CommandType.addEntry:
|
|
ret = Command.GCommandDeleteTimeTableEntry( target, -1, track, command.item );
|
|
m_group_vsq[track].Add( (TimeTableEntry)command.item.Clone() );
|
|
m_group_vsq[track].Sort();
|
|
break;
|
|
case CommandType.deleteEntry:
|
|
ret = Command.GCommandAddTimeTableEntry( target, -1, track, command.item );
|
|
m_group_vsq[track].Remove( command.item );
|
|
break;
|
|
case CommandType.editEntry:
|
|
ret = Command.GCommandEditTimeTableEntry( target, -1, track, entry, m_group_vsq[track][entry] );
|
|
m_group_vsq[track][entry] = (TimeTableEntry)command.item.Clone();
|
|
break;
|
|
case CommandType.addTimeTable:
|
|
ret = Command.GCommandDeleteTimeTable( target, -1, m_group_vsq.Count );
|
|
m_group_vsq.Insert( command.track, (TimeTable)command.table.Clone() );
|
|
break;
|
|
case CommandType.deleteTimeTable:
|
|
ret = Command.GCommandAddTimeTable( target, -1, track, m_group_vsq[track] );
|
|
m_group_vsq.RemoveAt( command.track );
|
|
break;
|
|
case CommandType.editTimeTable:
|
|
ret = Command.GCommandEditTimeTable( target, -1, track, m_group_vsq[track] );
|
|
m_group_vsq[command.track].Clear();
|
|
m_group_vsq[command.track] = (TimeTable)command.table.Clone();
|
|
break;
|
|
case CommandType.editGroup:
|
|
ret = Command.GCommandEditGroup( target, -1, m_group_vsq );
|
|
m_group_vsq = null;
|
|
m_group_vsq = (TimeTableGroup)command.tablegroup.Clone();
|
|
break;
|
|
case CommandType.shiftTimeTable:
|
|
ret = Command.GCommandShiftTimeTable( target, track, -command.floatValue );
|
|
for ( int i = 0; i < m_group_vsq[track].Count; i++ ) {
|
|
m_group_vsq[track][i].begin += command.floatValue;
|
|
m_group_vsq[track][i].end += command.floatValue;
|
|
}
|
|
break;
|
|
}
|
|
#endregion
|
|
break;
|
|
case TimeTableType.whole:
|
|
#region whole
|
|
switch ( command.type ) {
|
|
case CommandType.changePluginConfig:
|
|
ret = Command.GCommandChangePluginConfig( track, m_plugins_config[track].Config );
|
|
m_plugins_config[command.track].Config = command.str;
|
|
// キャラクタ描画用プラグインの場合は、該当キャラクタトラックのグループ番号に応じて、command.group(>=0)に値がセットされる
|
|
if ( command.group >= 0 ) {
|
|
m_groups_character[command.group].Character.PluginConfig.Config = command.str;
|
|
}
|
|
m_plugins[command.track].Instance.Config = command.str;
|
|
break;
|
|
case CommandType.changeFps:
|
|
ret = Command.GCommandChangeFps( m_dwRate, m_dwScale );
|
|
DwRate = command.dwRate;
|
|
DwScale = command.dwScale;
|
|
break;
|
|
case CommandType.changeVideoSize:
|
|
ret = Command.GCommandChangeVideoSize( m_movieSize );
|
|
m_movieSize = command.size;
|
|
break;
|
|
case CommandType.shiftTimeTable:
|
|
ret = Command.GCommandShiftTimeTable( TimeTableType.whole, -1, -command.floatValue );
|
|
float shift = command.floatValue;
|
|
// vsq
|
|
shiftTimeTable( ref m_group_vsq, shift );
|
|
// character
|
|
for ( int i = 0; i < m_groups_character.Count; i++ ) {
|
|
TimeTableGroup tmp = m_groups_character[i];
|
|
shiftTimeTable( ref tmp, shift );
|
|
m_groups_character[i] = tmp;
|
|
}
|
|
// another
|
|
shiftTimeTable( ref m_group_another, shift );
|
|
// plugin
|
|
shiftTimeTable( ref m_group_plugin, shift );
|
|
// telop
|
|
for ( int i = 0; i < m_telop_ex2.Count; i++ ) {
|
|
m_telop_ex2[i].Start += shift;
|
|
m_telop_ex2[i].End += shift;
|
|
}
|
|
break;
|
|
case CommandType.setMP3:
|
|
ret = Command.GCommandSetMp3( m_audioFile );
|
|
m_audioFile = command.str;
|
|
break;
|
|
case CommandType.changeBackgroundColor:
|
|
ret = Command.GCommandChangeBackgroundColor( CANVAS_BACKGROUND );
|
|
CANVAS_BACKGROUND = command.color;
|
|
break;
|
|
}
|
|
#endregion
|
|
break;
|
|
}
|
|
if ( command.child != null ) {
|
|
ret.child = Execute( command.child );
|
|
}
|
|
if ( CommandExecuted != null ) {
|
|
CommandExecuted( command.target, command.type );
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
private void shiftTimeTable( ref TimeTableGroup table, float shift ) {
|
|
for ( int track = 0; track < table.Count; track++ ) {
|
|
for ( int entry = 0; entry < table[track].Count; entry++ ) {
|
|
table[track][entry].begin += shift;
|
|
table[track][entry].end += shift;
|
|
}
|
|
}
|
|
}
|
|
|
|
public IEnumerable<ZorderItem> GetZorderItemEnumerator() {
|
|
for( int i = 0; i < m_groups_character.Count; i++ ) {
|
|
yield return new ZorderItem( m_groups_character[i].Text, ZorderItemType.character, i );
|
|
}
|
|
for( int i = 0; i < m_group_another.Count; i++ ) {
|
|
yield return new ZorderItem( m_group_another[i].Text, ZorderItemType.another, i );
|
|
}
|
|
for( int i = 0; i < m_telop_ex2.Count; i++ ) {
|
|
yield return new ZorderItem( m_telop_ex2[i].Text, ZorderItemType.telop, m_telop_ex2[i].ID );
|
|
}
|
|
}
|
|
|
|
public IEnumerable<BarLineType> GetBarLineTypeEnumerator( QuantizeMode mode, bool triplet ) {
|
|
int local_denominator;
|
|
int local_numerator;
|
|
int local_clock;
|
|
int local_bar_count;
|
|
int clock_step;
|
|
int end_clock;
|
|
int clock_per_bar;
|
|
for( int i = 0; i < m_timesig_ex.Count; i++ ) {
|
|
local_denominator = m_timesig_ex[i].Denominator;
|
|
local_numerator = m_timesig_ex[i].Numerator;
|
|
local_clock = m_timesig_ex[i].Clock;
|
|
local_bar_count = m_timesig_ex[i].BarCount;
|
|
clock_per_bar = 480 * 4 * local_numerator / local_denominator;
|
|
clock_step = 480 * 4 / local_denominator;
|
|
switch( mode ) {
|
|
case QuantizeMode.off:
|
|
clock_step = 480 * 4 / local_denominator;
|
|
break;
|
|
case QuantizeMode.q04:
|
|
clock_step = 480 * 4 / 4;
|
|
break;
|
|
case QuantizeMode.q08:
|
|
clock_step = 480 * 4 / 8;
|
|
break;
|
|
case QuantizeMode.q16:
|
|
clock_step = 480 * 4 / 16;
|
|
break;
|
|
case QuantizeMode.q32:
|
|
clock_step = 480 * 4 / 32;
|
|
break;
|
|
case QuantizeMode.q64:
|
|
clock_step = 480 * 4 / 64;
|
|
break;
|
|
}
|
|
if ( mode != QuantizeMode.off && triplet ) {
|
|
clock_step = clock_step * 4 / 3;
|
|
}
|
|
if( i == m_timesig_ex.Count - 1 ) {
|
|
double tempo;
|
|
if( m_tempo.Count > 0 ) {
|
|
tempo = m_tempo[m_tempo.Count - 1].Tempo;
|
|
} else {
|
|
tempo = m_base_tempo;
|
|
}
|
|
end_clock = (int)((m_totalSec - SecFromClock( m_timesig_ex[i].Clock ) + 1.0) * tpq_sec / tempo);
|
|
} else {
|
|
end_clock = m_timesig_ex[i + 1].Clock;
|
|
}
|
|
// todo: SettingsEx+GetBarLineTypeEnumerator; clock_per_barがclock_stepの整数倍とならない場合の処理
|
|
for( int clock = local_clock; clock < end_clock; clock += clock_step ) {
|
|
if( (clock - local_clock) % clock_per_bar == 0 ) {
|
|
yield return new BarLineType( SecFromClock( clock ), true, false );
|
|
} else {
|
|
yield return new BarLineType( SecFromClock( clock ), false, false );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 指定したクロックにおける、clock=0からの演奏経過時間(sec)
|
|
/// </summary>
|
|
/// <param name="clock"></param>
|
|
/// <returns></returns>
|
|
private double SecFromClock( int clock ) {
|
|
if( m_tempo.Count == 0 ) {
|
|
return (double)m_base_tempo * (double)clock / tpq_sec;
|
|
} else {
|
|
int index = 0;
|
|
for( int i = 0; i < m_tempo.Count; i++ ) {
|
|
if( clock <= m_tempo[i].Clock ) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
return m_tempo[index].Time + (double)(m_tempo[index].Tempo) * (clock - m_tempo[index].Clock) / tpq_sec;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|