[vConnect/trunk/stand2.0] TempoListに2個以上のテンポ変更が追加できる構造に変えた
@@ -8,36 +8,26 @@ | ||
8 | 8 | |
9 | 9 | class TempoListTest : public CppUnit::TestFixture { |
10 | 10 | public: |
11 | - void testConstruct() | |
11 | + void testTickToSecond() | |
12 | 12 | { |
13 | 13 | TempoList list; |
14 | - CPPUNIT_ASSERT_EQUAL( 120.0, list.getTempo() ); | |
14 | + CPPUNIT_ASSERT_EQUAL( 0.5, list.tickToSecond( 480 ) ); | |
15 | 15 | } |
16 | 16 | |
17 | - void testSetParameter() | |
17 | + void testPush() | |
18 | 18 | { |
19 | 19 | TempoList list; |
20 | - list.setParameter( "60", "" ); | |
21 | - CPPUNIT_ASSERT_EQUAL( 60.0, list.getTempo() ); | |
22 | - } | |
20 | + list.push( 0, 100.0 ); // 0.6 s / beat | |
21 | + list.push( 480, 50.0 ); // 1.2 s / beat | |
23 | 22 | |
24 | - void testSecondToTick() | |
25 | - { | |
26 | - TempoList list; | |
27 | - CPPUNIT_ASSERT_EQUAL( (long)480, list.secondToTick( 0.5 ) ); | |
23 | + CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, list.tickToSecond( 0 ), DBL_EPSILON ); | |
24 | + CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.6, list.tickToSecond( 480 ), DBL_EPSILON ); | |
25 | + CPPUNIT_ASSERT_DOUBLES_EQUAL( (double)1.8, list.tickToSecond( 960 ), DBL_EPSILON ); | |
28 | 26 | } |
29 | 27 | |
30 | - void testTickToSecond() | |
31 | - { | |
32 | - TempoList list; | |
33 | - CPPUNIT_ASSERT_EQUAL( 0.5, list.tickToSecond( 480 ) ); | |
34 | - } | |
35 | - | |
36 | 28 | CPPUNIT_TEST_SUITE( TempoListTest ); |
37 | - CPPUNIT_TEST( testConstruct ); | |
38 | - CPPUNIT_TEST( testSetParameter ); | |
39 | - CPPUNIT_TEST( testSecondToTick ); | |
40 | 29 | CPPUNIT_TEST( testTickToSecond ); |
30 | + CPPUNIT_TEST( testPush ); | |
41 | 31 | CPPUNIT_TEST_SUITE_END(); |
42 | 32 | }; |
43 | 33 | REGISTER_TEST_SUITE( TempoListTest ); |
@@ -989,7 +989,7 @@ | ||
989 | 989 | mControlCurves.resize( mVsq.controlCurves.size() ); |
990 | 990 | for( unsigned int i = 0; i < mControlCurves.size(); i++ ) |
991 | 991 | { |
992 | - mVsq.controlCurves[i].getList( mControlCurves[i], mVsq.getTempo() ); | |
992 | + mVsq.controlCurves[i].getList( mControlCurves[i], mVsq.vsqTempoBp ); | |
993 | 993 | } |
994 | 994 | } |
995 | 995 |
@@ -19,6 +19,7 @@ | ||
19 | 19 | #include <string> |
20 | 20 | #include <vector> |
21 | 21 | #include "BP.h" |
22 | +#include "TempoList.h" | |
22 | 23 | #include "../FrameBP.h" |
23 | 24 | |
24 | 25 | namespace vconnect |
@@ -28,7 +29,12 @@ | ||
28 | 29 | class BPList |
29 | 30 | { |
30 | 31 | public: |
31 | - void getList( vector<FrameBP> &dst, double tempo ); | |
32 | + /** | |
33 | + * このインスタンスが表現するコントロールカーブの時間変化を、FrameBP の配列に変換する | |
34 | + * @param dst 変換後配列の格納先 | |
35 | + * @param tempo 秒時の算出に必要なテンポ変更リスト | |
36 | + */ | |
37 | + void getList( vector<FrameBP> &dst, TempoList &tempo ); | |
32 | 38 | |
33 | 39 | void setParameter( long tick, int value ); |
34 | 40 |
@@ -83,10 +83,10 @@ | ||
83 | 83 | return this->events.endTick; |
84 | 84 | } |
85 | 85 | |
86 | - double Sequence::getTempo() | |
86 | + /*double Sequence::getTempo() | |
87 | 87 | { |
88 | 88 | return this->vsqTempoBp.getTempo(); |
89 | - } | |
89 | + }*/ | |
90 | 90 | |
91 | 91 | Sequence::Sequence() |
92 | 92 | { |
@@ -166,7 +166,7 @@ | ||
166 | 166 | this->setParamOtoIni( singerName, otoIniPath, encodingOtoIni ); |
167 | 167 | }else if( search.compare( OBJ_NAME_TEMPO ) == 0 ){ |
168 | 168 | // [Tempo] |
169 | - this->vsqTempoBp.setParameter( left, right ); | |
169 | + this->vsqTempoBp.push( 0L, atof( left.c_str() ) ); | |
170 | 170 | }else if( search.find( "[ID#" ) == 0 ){ |
171 | 171 | // ID |
172 | 172 | Map<string, Event *>::iterator i; |
@@ -0,0 +1,32 @@ | ||
1 | +/* | |
2 | + * TempoBP.h | |
3 | + * Copyright © 2012 kbinani | |
4 | + * | |
5 | + * This file is part of vConnect-STAND. | |
6 | + * | |
7 | + * vConnect-STAND is free software; you can redistribute it and/or | |
8 | + * modify it under the terms of the GPL License. | |
9 | + * | |
10 | + * vConnect-STAND is distributed in the hope that it will be useful, | |
11 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
13 | + */ | |
14 | +#ifndef __vconnect_TempoBP_h__ | |
15 | +#define __vconnect_TempoBP_h__ | |
16 | + | |
17 | +namespace vconnect{ | |
18 | + class TempoBP{ | |
19 | + public: | |
20 | + /** | |
21 | + * BPM 単位のテンポ値 | |
22 | + */ | |
23 | + double tempo; | |
24 | + | |
25 | + /** | |
26 | + * 秒単位の時刻 | |
27 | + */ | |
28 | + double time; | |
29 | + }; | |
30 | +} | |
31 | + | |
32 | +#endif |
@@ -73,11 +73,6 @@ | ||
73 | 73 | int getSingerIndex( string singer_name ); |
74 | 74 | |
75 | 75 | /// <summary> |
76 | - /// テンポ値を取得します. | |
77 | - /// </summary> | |
78 | - double getTempo(); | |
79 | - | |
80 | - /// <summary> | |
81 | 76 | /// シーケンスの長さ(tick単位)を取得します. |
82 | 77 | /// </summary> |
83 | 78 | /// <returns>シーケンスの長さ(tick単位)</returns> |
@@ -19,19 +19,66 @@ | ||
19 | 19 | { |
20 | 20 | const double TempoList::DEFAULT_TEMPO = 120.0; |
21 | 21 | |
22 | - void TempoList::setParameter( string left, string right ) | |
22 | + double TempoList::tickToSecond( long tick ) | |
23 | 23 | { |
24 | - tempo = atof( left.c_str() ); | |
24 | + if( false == this->isUpdated ){ | |
25 | + this->updateTempoInfo(); | |
26 | + } | |
27 | + double secPerClock; | |
28 | + double coeff = 60.0 / Sequence::getTickPerBeat(); | |
29 | + map<long, TempoBP>::reverse_iterator i = this->points.rbegin(); | |
30 | + for( ; i != this->points.rend(); i++ ){ | |
31 | + if( i->first < tick ){ | |
32 | + double init = i->second.time; | |
33 | + long delta = tick - i->first; | |
34 | + secPerClock = coeff / i->second.tempo; | |
35 | + return init + delta * secPerClock; | |
36 | + } | |
37 | + } | |
38 | + | |
39 | + secPerClock = coeff / TempoList::DEFAULT_TEMPO; | |
40 | + return tick * secPerClock; | |
25 | 41 | } |
26 | 42 | |
27 | - long TempoList::secondToTick( double second ) | |
43 | + void TempoList::updateTempoInfo() | |
28 | 44 | { |
29 | - /* In This Code, only static tempo is available */ | |
30 | - return (long)(second / 60.0 * tempo * Sequence::getTickPerBeat()); | |
45 | + TempoBP first; | |
46 | + first.tempo = TempoList::DEFAULT_TEMPO; | |
47 | + first.time = 0.0; | |
48 | + if( this->points.size() == 0 ){ | |
49 | + this->points.insert( make_pair( 0L, first ) ); | |
50 | + }else{ | |
51 | + if( this->points.begin()->first != 0 ){ | |
52 | + this->points.insert( make_pair( 0L, first ) ); | |
53 | + } | |
54 | + } | |
55 | + double coeff = 60.0 / Sequence::getTickPerBeat(); | |
56 | + double lastTime; | |
57 | + long lastClock; | |
58 | + double lastTempo; | |
59 | + map<long, TempoBP>::iterator i = this->points.begin(); | |
60 | + for( ; i != this->points.end(); i++ ){ | |
61 | + if( i == this->points.begin() ){ | |
62 | + i->second.time = 0.0; | |
63 | + lastClock = 0; | |
64 | + lastTempo = i->second.tempo; | |
65 | + lastTime = i->second.time; | |
66 | + }else{ | |
67 | + i->second.time = lastTime + (i->first - lastClock) * coeff / lastTempo; | |
68 | + lastClock = i->first; | |
69 | + lastTempo = i->second.tempo; | |
70 | + lastTime = i->second.time; | |
71 | + } | |
72 | + } | |
73 | + | |
74 | + this->isUpdated = true; | |
31 | 75 | } |
32 | 76 | |
33 | - double TempoList::tickToSecond( long tick ) | |
77 | + void TempoList::push( long tick, double tempo ) | |
34 | 78 | { |
35 | - return 60.0 / tempo * (double)tick / Sequence::getTickPerBeat(); | |
79 | + this->isUpdated = false; | |
80 | + TempoBP point; | |
81 | + point.tempo = tempo; | |
82 | + this->points.insert( make_pair( tick, point ) ); | |
36 | 83 | } |
37 | 84 | } |
@@ -16,6 +16,8 @@ | ||
16 | 16 | #define __TempoList_h__ |
17 | 17 | |
18 | 18 | #include <string> |
19 | +#include <map> | |
20 | +#include "TempoBP.h" | |
19 | 21 | |
20 | 22 | using namespace std; |
21 | 23 |
@@ -31,30 +33,34 @@ | ||
31 | 33 | |
32 | 34 | private: |
33 | 35 | /** |
34 | - * テンポ値 | |
36 | + * tick 単位の時刻をキーとした、テンポ変更点の連想配列 | |
35 | 37 | */ |
36 | - double tempo; | |
38 | + std::map<long, TempoBP> points; | |
37 | 39 | |
40 | + /** | |
41 | + * points フィールドの中身のテンポ変更点の時刻が更新されたかどうか | |
42 | + */ | |
43 | + bool isUpdated; | |
44 | + | |
38 | 45 | public: |
39 | - TempoList() | |
40 | - { | |
41 | - this->tempo = DEFAULT_TEMPO; | |
46 | + TempoList(){ | |
47 | + this->isUpdated = false; | |
42 | 48 | } |
43 | 49 | |
44 | - void setParameter( string left, string right ); | |
50 | + /** | |
51 | + * @brief テンポ値と時刻のセットを、テンポリストに追加する | |
52 | + * @param tick tick 単位の時刻 | |
53 | + * @param tempo テンポ値 | |
54 | + */ | |
55 | + void push( long tick, double tempo ); | |
45 | 56 | |
46 | - long secondToTick( double second ); | |
47 | - | |
48 | 57 | double tickToSecond( long tick ); |
49 | 58 | |
59 | + private: | |
50 | 60 | /** |
51 | - * テンポ値を取得する | |
52 | - * @return テンポ値 | |
61 | + * リスト内のテンポ変更情報の秒単位の時刻部分を更新する | |
53 | 62 | */ |
54 | - double getTempo() | |
55 | - { | |
56 | - return this->tempo; | |
57 | - } | |
63 | + void updateTempoInfo(); | |
58 | 64 | }; |
59 | 65 | } |
60 | 66 | #endif |
@@ -33,17 +33,18 @@ | ||
33 | 33 | data.push_back( current ); |
34 | 34 | } |
35 | 35 | |
36 | - void BPList::getList( vector<FrameBP>& dst, double tempo ) | |
36 | + void BPList::getList( vector<FrameBP>& dst, TempoList &tempo ) | |
37 | 37 | { |
38 | 38 | vector<BP>::size_type size = this->data.size(); |
39 | 39 | dst.clear(); |
40 | 40 | dst.resize( size ); |
41 | - double framePeriod = Configuration::getMilliSecondsPerFrame(); | |
41 | + double framePerMilliSecond = 1.0 / Configuration::getMilliSecondsPerFrame(); | |
42 | 42 | for( vector<BP>::size_type i = 0; i < size; i++ ){ |
43 | 43 | dst[i].value = this->data[i].value; |
44 | 44 | dst[i].frameTime = INT_MAX; // the value will continue till this time. |
45 | 45 | if( i ){ |
46 | - dst[i - 1].frameTime = (long)(1000.0 * (double)(this->data[i].tick) / 480.0 * 60.0 / tempo / framePeriod); | |
46 | + double second = tempo.tickToSecond( this->data[i].tick ); | |
47 | + dst[i - 1].frameTime = 1000.0 * second * framePerMilliSecond; | |
47 | 48 | } |
48 | 49 | } |
49 | 50 | } |