1
1
#include <screen_sing.h>
3
#include <boost/format.hpp>
3
5
#include <pitch_graph.h>
4
6
#include <cairotosdl.h>
6
CScreenSing::CScreenSing(char * name)
7
: pitchGraph(CScreenManager::getSingletonPtr()->getWidth(), CScreenManager::getSingletonPtr()->getHeight())
8
CScreenSing::CScreenSing(std::string const& name, unsigned int width, unsigned int height, Analyzer const& analyzer):
9
CScreen(name,width,height), m_analyzer(analyzer), pitchGraph(width, height)
10
11
video = new CVideo();
11
12
SDL_Surface *screen;
12
previousFirstTimestamp = -1;
14
CScreenManager * sm = CScreenManager::getSingletonPtr();
14
CScreenManager* sm = CScreenManager::getSingletonPtr();
15
15
screen = sm->getSDLScreen();
17
videoSurf = SDL_AllocSurface( screen->flags,
17
videoSurf = SDL_AllocSurface(screen->flags,
20
20
screen->format->BitsPerPixel,
21
21
screen->format->Rmask,
22
22
screen->format->Gmask,
23
23
screen->format->Bmask,
24
24
screen->format->Amask);
25
25
SDL_SetAlpha(videoSurf, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
26
//SDL_FillRect(videoSurf,NULL,0xffffff);
27
backgroundSurf = SDL_AllocSurface( screen->flags,
26
backgroundSurf = SDL_AllocSurface(screen->flags,
30
29
screen->format->BitsPerPixel,
35
34
SDL_SetAlpha(backgroundSurf, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
36
SDL_FillRect(backgroundSurf,NULL,SDL_MapRGB(backgroundSurf->format, 255, 255, 255));
37
theme = new CThemeSing();
35
SDL_FillRect(backgroundSurf,NULL,SDL_MapRGB(backgroundSurf->format, 255, 255, 255));
40
CScreenSing::~CScreenSing()
43
SDL_FreeSurface(videoSurf);
45
SDL_FreeSurface(backgroundSurf);
38
CScreenSing::~CScreenSing() {
39
if (videoSurf) SDL_FreeSurface(videoSurf);
40
if (backgroundSurf) SDL_FreeSurface(backgroundSurf);
51
void CScreenSing::enter( void )
54
CScreenManager * sm = CScreenManager::getSingletonPtr();
55
CSong * song = sm->getSong();
57
if( song->video != NULL ) {
58
snprintf(buff,1024,"%s/%s",song->path,song->video);
59
fprintf(stdout,"Now playing: (%d): %s\n",sm->getSongId(),buff);
60
video->loadVideo(buff,videoSurf,sm->getWidth(),sm->getHeight());
61
} else if ( song->background != NULL) {
62
SDL_BlitSurface(song->backgroundSurf,NULL,backgroundSurf,NULL);
63
SDL_BlitSurface(theme->bg->getSDLSurface(),NULL,backgroundSurf,NULL);
64
SDL_BlitSurface(theme->p1box->getSDLSurface(),NULL,backgroundSurf,NULL);
66
SDL_FillRect(backgroundSurf,NULL,SDL_MapRGB(backgroundSurf->format, 255, 255, 255));
67
SDL_BlitSurface(theme->bg->getSDLSurface(),NULL,backgroundSurf,NULL);
68
SDL_BlitSurface(theme->p1box->getSDLSurface(),NULL,backgroundSurf,NULL);
44
void CScreenSing::enter() {
45
bool video_ok = false;
46
CScreenManager* sm = CScreenManager::getSingletonPtr();
47
Song& song = sm->getSongs()->current();
48
theme = new CThemeSing(m_width, m_height);
49
SDL_FillRect(backgroundSurf,NULL,SDL_MapRGB(backgroundSurf->format, 255, 255, 255));
50
if (!song.video.empty()) {
51
std::string file = song.path + song.video;
52
std::cout << "Now playing: " << file << std::endl;
53
video_ok = video->loadVideo(file, videoSurf, m_width, m_height);
56
SDL_Surface* bg = song.getBackground();
57
if (bg) SDL_BlitSurface(bg, NULL, backgroundSurf, NULL);
59
SDL_BlitSurface(theme->bg->getSDLSurface(),NULL,backgroundSurf,NULL);
60
SDL_BlitSurface(theme->p1box->getSDLSurface(),NULL,backgroundSurf,NULL);
70
61
backgroundSurf_id = sm->getVideoDriver()->initSurface(backgroundSurf);
71
62
theme_id = sm->getVideoDriver()->initSurface(theme->theme->getCurrent());
72
63
pitchGraph_id = sm->getVideoDriver()->initSurface(pitchGraph.getCurrent());
73
snprintf(buff,1024,"%s/%s",song->path,song->mp3);
74
fprintf(stdout,"Now playing: (%d): %s\n",sm->getSongId(),buff);
75
sm->getAudio()->playMusic(buff);
76
lyrics = new CLyrics( song->notes, song->gap, song->bpm[0].bpm );
77
song->score[0].score = 0;
78
song->score[0].hits = 0;
79
song->score[0].total = 0;
64
std::string file = song.path + song.mp3;
65
std::cout << "Now playing: " << file << std::endl;
66
CAudio& audio = *sm->getAudio();
67
audio.playMusic(file.c_str());
68
lyrics = new Lyrics(song.notes);
71
audio.wait(); // Until playback starts
83
void CScreenSing::exit( void )
74
void CScreenSing::exit() {
85
75
CScreenManager::getSingletonPtr()->getAudio()->stopMusic();
86
76
video->unloadVideo();
87
77
SDL_FillRect(videoSurf,NULL,0xffffff);
90
81
pitchGraph.clear();
93
void CScreenSing::manageEvent( SDL_Event event )
95
CScreenManager * sm = CScreenManager::getSingletonPtr();
99
keypressed = event.key.keysym.sym;
100
if( keypressed == SDLK_ESCAPE || keypressed == SDLK_q ) {
101
sm->activateScreen("Songs");
102
} else if( keypressed == SDLK_SPACE || keypressed == SDLK_p ) {
103
sm->getAudio()->togglePause();
104
} else if( keypressed == SDLK_PLUS ) {
106
} else if( keypressed == SDLK_MINUS ) {
108
} else if( keypressed == SDLK_LEFT ) {
109
sm->getAudio()->seek(-5000);
110
} else if( keypressed == SDLK_RIGHT ) {
111
sm->getAudio()->seek(5000);
112
} else if( keypressed == SDLK_UP ) {
113
sm->getAudio()->seek(30000);
114
} else if( keypressed == SDLK_DOWN ) {
115
sm->getAudio()->seek(-30000);
84
void CScreenSing::manageEvent(SDL_Event event) {
85
if (event.type == SDL_KEYDOWN) {
86
CScreenManager* sm = CScreenManager::getSingletonPtr();
87
CAudio& audio = *sm->getAudio();
88
int key = event.key.keysym.sym;
89
if (key == SDLK_ESCAPE || key == SDLK_q) sm->activateScreen(m_sentence.empty() ? "Score" : "Songs");
90
else if (key == SDLK_SPACE || key == SDLK_p) sm->getAudio()->togglePause();
91
else if (key == SDLK_PLUS) playOffset += 0.02;
92
else if (key == SDLK_MINUS) playOffset -= 0.02;
93
else if (key == SDLK_HOME) audio.seek(-audio.getPosition());
94
else if (key == SDLK_RETURN && !m_sentence.empty()) {
95
double diff = m_sentence[0].begin - 1.0 - audio.getPosition();
96
if (diff > 0.0) audio.seek(diff);
98
else if (key == SDLK_LEFT) audio.seek(-5.0);
99
else if (key == SDLK_RIGHT) audio.seek(5.0);
100
else if (key == SDLK_UP) audio.seek(30.0);
101
else if (key == SDLK_DOWN) audio.seek(-30.0);
120
void CScreenSing::draw( void )
122
CScreenManager * sm = CScreenManager::getSingletonPtr();
123
CRecord * record = sm->getRecord();
124
CSong * song = sm->getSong();
127
float resFactorX = sm->getWidth()/800.;
128
float resFactorY = sm->getHeight()/600.;
129
float resFactorAvg = (resFactorX + resFactorY)/2.;
131
theme->theme->clear();
133
if( !sm->getAudio()->isPlaying() ) {
134
sm->activateScreen("Songs");
105
void CScreenSing::draw() {
106
CScreenManager* sm = CScreenManager::getSingletonPtr();
107
if (!sm->getAudio()->isPlaying()) {
108
sm->activateScreen("Score");
139
freq = record->getFreq();
140
note = record->getNoteId();
143
// draw lines across the screen
145
unsigned int numOctaves = (song->noteMax+11)/12 - song->noteMin/12;
146
unsigned int lowestC = (song->noteMin/12) * 12; // the C below noteMin
147
if( numOctaves < 3 ) numOctaves = 3;
150
linerect.stroke_col.r = linerect.stroke_col.g = linerect.stroke_col.b = 0;
151
linerect.stroke_col.a = 0.9;
152
linerect.stroke_width = 1.*resFactorAvg;
153
linerect.svg_width = sm->getWidth();
154
linerect.svg_height = sm->getHeight();
155
linerect.height = 1.*resFactorY;
156
linerect.fill_col.a = 0.5;
158
linerect.width = sm->getWidth();
159
linerect.fill_col.r = 50;
160
linerect.fill_col.g = 50;
161
linerect.fill_col.b = 50;
162
linerect.final_height = 0;
163
linerect.final_width = 0;
164
// draw lines for the C notes (thick)
165
for( unsigned int i = 0 ; i <= numOctaves ; i++ ) {
166
if( i <= (song->noteMax-lowestC)/12 ) {
167
linerect.y = sm->getHeight() * 3 / 4 - i * sm->getHeight() / 2 / numOctaves;
168
theme->theme->DrawRect(linerect);
171
linerect.stroke_width = 0;
172
// draw the other lines in between
173
for( unsigned int i = 0 ; i < numOctaves ; i++ ) {
174
for( int j = 1 ; j < 12 ; j++ ) {
175
if( i * 12 + j + (lowestC/12) * 12 <= (unsigned int)song->noteMax){
176
linerect.y = sm->getHeight() * 3 / 4 - ( i * 12 + j ) * sm->getHeight() / 24 / numOctaves;
177
theme->theme->DrawRect(linerect);
111
Song& song = sm->getSongs()->current();
112
float freq = m_analyzer.getFreq();
113
float resFactorX = m_width / 800.0;
114
float resFactorY = m_height / 600.0;
115
float resFactorAvg = (resFactorX + resFactorY) / 2.0;
117
theme->theme->clear();
182
118
// Get the time in the song
183
unsigned int time = sm->getAudio()->getPosition();
184
// Test is playOffset + time > 0
185
if( playOffset < 0 && time < (unsigned int)(playOffset*-1) )
190
double songPercent = (double)time / (double)sm->getAudio()->getLength();
119
double time = sm->getAudio()->getPosition();
120
time = std::max(0.0, time + playOffset);
121
double songPercent = time / sm->getAudio()->getLength();
123
song.update(time, freq);
191
124
// Here we compute all about the lyrics
192
lyrics->updateSentences( time );
193
char * sentenceNextSentence = lyrics->getSentenceNext();
194
char * sentencePast = lyrics->getSentencePast();
195
char * sentenceNow = lyrics->getSentenceNow();
196
char * sentenceFuture = lyrics->getSentenceFuture();
197
char * sentenceWhole = lyrics->getSentenceWhole();
199
sentence = lyrics->getCurrentSentence();
200
if( sentence.size() && previousFirstTimestamp != sentence[0]->timestamp ) {
201
previousFirstTimestamp = sentence[0]->timestamp;
125
lyrics->updateSentences(time);
126
std::string sentenceNextSentence = lyrics->getSentenceNext();
127
std::string sentencePast = lyrics->getSentencePast();
128
std::string sentenceNow = lyrics->getSentenceNow();
129
std::string sentenceFuture = lyrics->getSentenceFuture();
130
std::string sentenceWhole = lyrics->getSentenceWhole();
205
131
// Draw the video
206
if( !video->isPlaying() && time > song->videoGap )
209
if( video->isPlaying() ) {
210
/* FIXME: make video work with opengl, SMPEG sets alpha channel to zero */
211
SDL_BlitSurface(videoSurf,NULL,backgroundSurf,NULL);
212
sm->getVideoDriver()->drawSurface(backgroundSurf);
213
sm->getVideoDriver()->drawSurface(theme->bg->getSDLSurface());
214
sm->getVideoDriver()->drawSurface(theme->p1box->getSDLSurface());
132
if (!video->isPlaying() && time > song.videoGap) video->play();
133
if (video->isPlaying()) {
134
SDL_BlitSurface(videoSurf,NULL,backgroundSurf,NULL);
135
sm->getVideoDriver()->drawSurface(backgroundSurf);
136
sm->getVideoDriver()->drawSurface(theme->bg->getSDLSurface());
137
sm->getVideoDriver()->drawSurface(theme->p1box->getSDLSurface());
216
139
sm->getVideoDriver()->drawSurface(backgroundSurf_id);
217
sm->getVideoDriver()->updateSurface(backgroundSurf_id , (SDL_Surface *) NULL);
140
sm->getVideoDriver()->updateSurface(backgroundSurf_id , (SDL_Surface *) NULL);
220
142
// Compute and draw the timer and the progressbar
223
sprintf(dateStr,"%.2u:%.2u",(time/1000)/60,(time/1000)%60);
224
theme->timertxt.text = dateStr;
225
theme->theme->PrintText(&theme->timertxt);
226
theme->progressfg.width = theme->progressfg.final_width * songPercent;
227
theme->theme->DrawRect(theme->progressfg);
232
sprintf(scoreStr,"%04d",int(song->score[0].score/10)*10);
233
theme->p1score.text = scoreStr;
234
theme->theme->PrintText(&theme->p1score);
143
theme->timertxt.text = (boost::format("%02u:%02u") % (unsigned(time) / 60) % (unsigned(time) % 60)).str();
144
theme->theme->PrintText(&theme->timertxt);
145
theme->progressfg.width = theme->progressfg.final_width * songPercent;
146
theme->theme->DrawRect(theme->progressfg);
148
theme->p1score.text = (boost::format("%04d") % song.getScore()).str();
149
theme->theme->PrintText(&theme->p1score);
237
150
// draw the sang note TODO: themed sang note
240
tmptxt = theme->timertxt; // use timertxt as template
241
tmptxt.text = record->getNoteStr(note);
243
tmptxt.y=sm->getHeight();
244
tmptxt.fontsize = 25;
245
theme->theme->PrintText(&tmptxt);
152
TThemeTxt tmptxt = theme->timertxt; // use timertxt as template
153
tmptxt.text = song.scale.getNoteStr(freq);
155
tmptxt.fontsize = 25;
156
theme->theme->PrintText(&tmptxt);
248
158
// compute and draw the text
249
unsigned int totalBpm;
251
if(sentence.size() ) {
252
totalBpm = sentence[sentence.size()-1]->length + sentence[sentence.size()-1]->timestamp - sentence[0]->timestamp;
253
bpmPixelUnit = (sm->getWidth() - 100.*resFactorX - 100.*resFactorX)/(totalBpm*1.0);
159
double sentenceBegin = m_sentence.empty() ? 0.0 : m_sentence[0].begin;
160
double sentenceDuration = 0.0;
161
double pixUnit = 0.0;
162
m_sentence = lyrics->getCurrentSentence();
163
if (!m_sentence.empty()) {
164
if (sentenceBegin != m_sentence[0].begin) {
166
sentenceBegin = m_sentence[0].begin;
168
sentenceDuration = m_sentence.back().end - sentenceBegin;
169
pixUnit = (m_width - 200.0 * resFactorX) / (sentenceDuration * 1.0);
260
tmprect.stroke_col.r = tmprect.stroke_col.g = tmprect.stroke_col.b = 0;
261
tmprect.stroke_col.a = 255;
262
tmprect.stroke_width = 2.*resFactorAvg;
263
tmprect.svg_width = sm->getWidth();
264
tmprect.svg_height = sm->getHeight();
265
tmprect.height = 10.*resFactorY;
266
tmprect.fill_col.a = 255;
173
// Compute and draw the "to start" cursor
174
if (time < sentenceBegin) {
175
double wait = sentenceBegin - time;
176
double value = 4.0 * wait / sentenceDuration;
177
if (value > 1.0) value = wait > 1.0 ? 0.0 : 1.0;
178
theme->tostartfg.height = theme->tostartfg.final_height * value;
179
theme->theme->DrawRect(theme->tostartfg);
181
int min = song.noteMin - 7;
182
int max = song.noteMax + 7;
183
double noteUnit = -0.5 * m_height / std::max(32, max - min);
184
double baseY = 0.5 * m_height - 0.5 * (min + max) * noteUnit;
187
linerect.svg_width = m_width;
188
linerect.svg_height = m_height;
190
linerect.width = m_width;
191
linerect.height = 0.0;
192
linerect.fill_col.r = 0.0;
193
linerect.fill_col.g = 0.0;
194
linerect.fill_col.b = 0.0;
195
linerect.fill_col.a = 0.0;
196
linerect.final_height = 0;
197
linerect.final_width = 0;
198
linerect.stroke_col.a = 0.7;
200
if (!m_sentence.empty()) {
201
for (int n = song.noteMin; n <= song.noteMax; ++n) {
202
linerect.stroke_width = (song.scale.isSharp(n) ? 0.5 : 1.5) * resFactorAvg;
204
linerect.stroke_col.r = 0.5;
205
linerect.stroke_col.g = 0.5;
206
linerect.stroke_col.b = 0.5;
208
linerect.stroke_col.r = 0.8;
209
linerect.stroke_col.g = 0.3;
210
linerect.stroke_col.b = 0.8;
212
linerect.y = baseY + n * noteUnit;
213
theme->theme->DrawRect(linerect);
218
tmprect.stroke_col.r = tmprect.stroke_col.g = tmprect.stroke_col.b = 0.5;
219
tmprect.stroke_col.a = 0.8;
220
tmprect.stroke_width = resFactorAvg;
221
tmprect.svg_width = m_width;
222
tmprect.svg_height = m_height;
223
tmprect.height = -noteUnit;
267
224
tmprect.final_height = 0;
268
225
tmprect.final_width = 0;
270
// Compute and draw the "to start" cursor
271
if (sentence.size()>0 && time < (sentence[0]->timestamp * 60 * 1000) / (song->bpm[0].bpm * 4 ) + song->gap){
272
float waitLen = sentence[0]->timestamp - (time - song->gap) * (song->bpm[0].bpm * 4) / 60 / 1000;
273
if( theme->tostartfg.final_height - waitLen * 5 < 0 )
274
waitLen = theme->tostartfg.final_height;
276
waitLen = theme->tostartfg.final_height - waitLen * 5;
278
theme->tostartfg.height = theme->tostartfg.final_height - waitLen;
279
theme->theme->DrawRect(theme->tostartfg);
282
for( unsigned int i = 0 ; i < sentence.size() ; i ++ ) {
283
int currentBpm = sentence[i]->timestamp - sentence[0]->timestamp;
284
int noteHeight=sm->getHeight()*3/4-((sentence[i]->note-lowestC)*sm->getHeight()/2/numOctaves/12);
286
// if C <= timestamp < N
287
if( time > ( (sentence[i]->timestamp+sentence[i]->length) * 60 * 1000) / ( song->bpm[0].bpm * 4 ) + song->gap ) {
289
int begin = (int) (currentBpm*bpmPixelUnit);
290
int end = (int) ((currentBpm+sentence[i]->length)*bpmPixelUnit);
291
tmprect.x = 105.*resFactorX + begin;
292
tmprect.y = y - 5.*resFactorY;
293
tmprect.width = 100.*resFactorX + end - tmprect.x;
294
tmprect.fill_col.r = 0;
295
tmprect.fill_col.g = 0;
296
tmprect.fill_col.b = 255;
297
theme->theme->DrawRect(tmprect);
298
// if N+d <= timestamp < E
299
} else if( time < ( (sentence[i]->timestamp) * 60 * 1000) / ( song->bpm[0].bpm * 4 ) + song->gap ) {
301
int begin = (int) (currentBpm*bpmPixelUnit);
302
int end = (int) ((currentBpm+sentence[i]->length)*bpmPixelUnit);
303
tmprect.x = 105.*resFactorX + begin;
304
tmprect.y = y - 5.*resFactorY;
305
tmprect.width = 100.*resFactorX + end - tmprect.x;
306
tmprect.fill_col.r = 200;
307
tmprect.fill_col.g = 200;
308
tmprect.fill_col.b = 200;
309
theme->theme->DrawRect(tmprect);
312
int begin = (int) (currentBpm*bpmPixelUnit);
313
int end = (int) ((currentBpm+sentence[i]->length)*bpmPixelUnit);
314
float note_start = (time - ( (sentence[i]->timestamp) * 60 * 1000) / ( song->bpm[0].bpm * 4 ) - song->gap);
315
float note_total = (sentence[i]->length) * 60 * 1000 / ( song->bpm[0].bpm * 4 );
316
int current = (int) ((currentBpm + note_start*sentence[i]->length/note_total)*bpmPixelUnit);
317
tmprect.x = 105.*resFactorX + begin;
318
tmprect.y = y - 5.*resFactorY;
319
tmprect.width = 100.*resFactorX + current - tmprect.x;
320
tmprect.fill_col.r = 0;
321
tmprect.fill_col.g = 0;
322
tmprect.fill_col.b = 255;
323
theme->theme->DrawRect(tmprect);
325
tmprect.x = 100.*resFactorX + current;
326
tmprect.y = y - 5.*resFactorY;
327
tmprect.width = 100.*resFactorX + end - tmprect.x;
328
tmprect.fill_col.r = 200;
329
tmprect.fill_col.g = 200;
330
tmprect.fill_col.b = 200;
331
theme->theme->DrawRect(tmprect);
333
// Lets find the nearest note from the song (diff in [-6,5])
334
int diff = (66+sentence[i]->note - note)%12-6;
335
int noteSingFinal = sentence[i]->note - diff;
336
int noteheight=((18*numOctaves-noteSingFinal+lowestC)*sm->getHeight()/2/numOctaves/12);
338
pitchGraph.renderPitch(
339
((float)noteheight/sm->getHeight()),
340
((double)current + 100)/sm->getWidth());
341
if( abs(diff) <= abs( 2 - sm->getDifficulty() ) )
342
song->score[0].hits++;
344
pitchGraph.renderPitch( 0.0, ((double)current + 100)/sm->getWidth());
346
song->score[0].total++;
347
float factor = ((float) sentence[i]->curMaxScore)/song->maxScore;
348
if( factor >= 0 && factor <= 1){
349
song->score[0].score = (int)(10000*factor * song->score[0].hits/song->score[0].total);
227
double baseX = 100.0 * resFactorX - sentenceBegin * pixUnit;
228
for (unsigned int i = 0; i < m_sentence.size(); ++i) {
229
if (m_sentence[i].begin > time) state = 3;
230
if (state == 0 && m_sentence[i].end > time) state = 1;
231
tmprect.y = baseY + m_sentence[i].note * noteUnit - 0.5 * tmprect.height;
232
double begin = (state == 2 ? time : m_sentence[i].begin);
233
double end = (state == 1 ? time : m_sentence[i].end);
234
tmprect.x = baseX + begin * pixUnit;
235
tmprect.width = (end - begin) * pixUnit;
237
tmprect.fill_col.r = 0.7;
238
tmprect.fill_col.g = 0.7;
239
tmprect.fill_col.b = 0.7;
240
tmprect.fill_col.a = 1.0;
242
switch (m_sentence[i].type) {
243
case Note::FREESTYLE:
244
tmprect.fill_col.r = 0.6;
245
tmprect.fill_col.g = 1.0;
246
tmprect.fill_col.b = 0.6;
247
tmprect.fill_col.a = 1.0;
250
tmprect.fill_col.r = 1.0;
251
tmprect.fill_col.g = 0.8;
252
tmprect.fill_col.b = 0.0;
253
tmprect.fill_col.a = 1.0;
256
tmprect.fill_col.r = 0.8;
257
tmprect.fill_col.g = 0.8;
258
tmprect.fill_col.b = 1.0;
259
tmprect.fill_col.a = 1.0;
354
tmptxt = theme->lyricspast;
355
tmptxt.text = sentenceWhole;
356
cairo_text_extents_t extents = theme->theme->GetTextExtents(tmptxt);
357
theme->lyricspast.x = (theme->lyricspast.svg_width - extents.width)/2;
358
theme->lyricspast.extents.x_advance = 0;
359
theme->lyricshighlight.extents.x_advance= 0;
361
if( sentencePast[0] ) {
362
theme->lyricspast.text = sentencePast;
363
theme->theme->PrintText(&theme->lyricspast);
366
if( sentenceNow[0] ) {
367
unsigned int length = lyrics->getCurrentNote()->length;
368
unsigned int timestamp = lyrics->getCurrentNote()->timestamp;
369
float length_ms = length * 60 * 1000 / ( song->bpm[0].bpm * 4 );
370
float timestamp_ms = timestamp * 60 * 1000 / ( song->bpm[0].bpm * 4 ) + song->gap;
371
float started_ms = time - timestamp_ms;
372
float factor = 1.2 - 0.2*started_ms/length_ms;
374
if( factor < 1.0 ) factor = 1.0;
375
if( factor > 1.2 ) factor = 1.2;
376
theme->lyricshighlight.x = theme->lyricspast.x + theme->lyricspast.extents.x_advance;
377
theme->lyricshighlight.text = sentenceNow;
378
theme->lyricshighlight.scale = factor;
379
theme->theme->PrintText(&theme->lyricshighlight);
382
if( sentenceFuture[0] ) {
383
theme->lyricsfuture.text = sentenceFuture;
384
theme->lyricsfuture.x = theme->lyricspast.x + theme->lyricspast.extents.x_advance + theme->lyricshighlight.extents.x_advance;
385
theme->theme->PrintText(&theme->lyricsfuture);
388
if( sentenceNextSentence[0] ) {
389
theme->lyricsnextsentence.text = sentenceNextSentence;
390
theme->lyricsnextsentence.extents = theme->theme->GetTextExtents(theme->lyricsnextsentence);
391
theme->lyricsnextsentence.x = (theme->lyricsnextsentence.svg_width - theme->lyricsnextsentence.extents.width)/2;
392
theme->theme->PrintText(&theme->lyricsnextsentence);
395
sm->getVideoDriver()->updateSurface(theme_id, theme->theme->getCurrent());
262
theme->theme->DrawRect(tmprect);
263
if (state == 1) { --i; state = 2; }
266
if (!m_sentence.empty()) {
267
double graphTime = (baseX + time * pixUnit) / m_width;
269
pitchGraph.renderPitch(0.0, graphTime, 0.0);
272
// Find the currently playing note or the next playing note (or the last note?)
273
while (i < m_sentence.size() && time > m_sentence[i].end) ++i;
274
Note const& n = m_sentence[i];
275
double volume = std::max(0.0, 1.0 + m_analyzer.getPeak() / 40.0);
276
pitchGraph.renderPitch((baseY + (n.note + n.diff(song.scale.getNote(freq))) * noteUnit) / m_height, graphTime, volume);
280
TThemeTxt tmptxt = theme->lyricspast;
281
tmptxt.text = sentenceWhole;
283
cairo_text_extents_t extents = theme->theme->GetTextExtents(tmptxt);
284
theme->lyricspast.x = (theme->lyricspast.svg_width - extents.width)/2;
286
oldfontsize = theme->lyricspast.fontsize;
287
while (theme->lyricspast.x < 0) {
288
theme->lyricspast.fontsize -= 2;
289
theme->lyricshighlight.fontsize -= 2;
290
theme->lyricsfuture.fontsize -= 2;
291
tmptxt = theme->lyricspast;
292
tmptxt.text = sentenceWhole;
293
cairo_text_extents_t extents = theme->theme->GetTextExtents(tmptxt);
294
theme->lyricspast.x = (theme->lyricspast.svg_width - extents.width)/2;
296
theme->lyricspast.extents.x_advance = 0;
297
theme->lyricshighlight.extents.x_advance= 0;
299
if (!sentencePast.empty()) {
300
theme->lyricspast.text = sentencePast;
301
theme->theme->PrintText(&theme->lyricspast);
303
if (!sentenceNow.empty()) {
304
Note* n = lyrics->getCurrentNote();
305
if (!n) throw std::logic_error("sentenceNow is not empty but current note is NULL");
306
double phase = (time - n->begin) / (n->end - n->begin);
307
double factor = std::min(1.2, std::max(1.0, 1.2 - 0.2 * phase));
308
theme->lyricshighlight.x = theme->lyricspast.x + theme->lyricspast.extents.x_advance;
309
theme->lyricshighlight.text = sentenceNow;
310
theme->lyricshighlight.scale = factor;
311
theme->theme->PrintText(&theme->lyricshighlight);
313
if (!sentenceFuture.empty()) {
314
theme->lyricsfuture.text = sentenceFuture;
315
theme->lyricsfuture.x = theme->lyricspast.x + theme->lyricspast.extents.x_advance + theme->lyricshighlight.extents.x_advance;
316
theme->theme->PrintText(&theme->lyricsfuture);
319
if (!sentenceNextSentence.empty()) {
320
theme->lyricsnextsentence.text = sentenceNextSentence;
321
theme->lyricsnextsentence.extents = theme->theme->GetTextExtents(theme->lyricsnextsentence);
322
theme->lyricsnextsentence.x = (theme->lyricsnextsentence.svg_width - theme->lyricsnextsentence.extents.width)/2;
323
while (theme->lyricsnextsentence.x < 0) {
324
theme->lyricsnextsentence.fontsize -= 2;
325
theme->lyricsnextsentence.extents = theme->theme->GetTextExtents(theme->lyricsnextsentence);
326
theme->lyricsnextsentence.x = (theme->lyricsnextsentence.svg_width - theme->lyricsnextsentence.extents.width)/2;
328
theme->theme->PrintText(&theme->lyricsnextsentence);
331
theme->lyricspast.fontsize = oldfontsize;
332
theme->lyricshighlight.fontsize = oldfontsize;
333
theme->lyricsfuture.fontsize = oldfontsize;
334
theme->lyricsnextsentence.fontsize = oldfontsize;
336
sm->getVideoDriver()->updateSurface(theme_id, theme->theme->getCurrent());
396
337
sm->getVideoDriver()->drawSurface(theme_id);
397
sm->getVideoDriver()->updateSurface(pitchGraph_id, pitchGraph.getCurrent());
338
sm->getVideoDriver()->updateSurface(pitchGraph_id, pitchGraph.getCurrent());
398
339
sm->getVideoDriver()->drawSurface(pitchGraph_id);