~ubuntu-branches/ubuntu/wily/ultrastar-ng/wily

« back to all changes in this revision

Viewing changes to src/screen_sing.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Miriam Ruiz, Miriam Ruiz, Mario Bonino, Jon Dowland, Ansgar Burchardt
  • Date: 2008-06-07 16:43:18 UTC
  • mfrom: (4.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080607164318-4cnzizck1tp8mrwp
Tags: 0.2.1-1
[ Miriam Ruiz ]
* New Upstream Release (Closes: #453132)
* Removed unneeded patches
* Added packages to build deps:
  + libtool
  + portaudio19-dev | portaudio-dev
  + libboost-dev, libboost-thread-dev, libboost-serialization-dev
  + libboost-program-options-dev, libboost-regex-dev
* Moved shared objects to private directory: /usr/lib/ultraster-ng
* Added rpath to binaries to search for shared objects in the private dir
* Uses ultrastar-ng-gstreamer as default, instead of ultrastar-ng-xine,
  since there are significantly less issues with GStreamer.
* Added patch to fix upstream desktop file
* Added -Wl,-as-needed to LDFLAGS
* Replaced fftw3-dev by libfftw3-dev in build dependencies.
* Standards-Version upgraded to 3.7.3

[ Mario Bonino ]
* Fixed data/Makefile.am to install .desktop file and icon

[ Jon Dowland ]
* add Homepage: control field to source stanza
* fix a bashism in debian/rules (Closes: #478634)

[ Ansgar Burchardt ]
* debian/control: Change XS-Vcs-* to Vcs-*
* Remove Homepage semi-field from description

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#include <screen_sing.h>
 
2
 
 
3
#include <boost/format.hpp>
2
4
#include <songs.h>
3
5
#include <pitch_graph.h>
4
6
#include <cairotosdl.h>
5
7
 
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)
8
10
{
9
 
        screenName = name;
10
11
        video = new CVideo();
11
12
        SDL_Surface *screen;
12
 
        previousFirstTimestamp = -1;
13
13
 
14
 
        CScreenManager * sm = CScreenManager::getSingletonPtr();
 
14
        CScreenManager* sm = CScreenManager::getSingletonPtr();
15
15
        screen = sm->getSDLScreen();
16
16
 
17
 
        videoSurf = SDL_AllocSurface( screen->flags,
18
 
                        sm->getWidth(),
19
 
                        sm->getHeight(),
 
17
        videoSurf = SDL_AllocSurface(screen->flags,
 
18
                        width,
 
19
                        height,
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,
28
 
                        sm->getWidth(),
29
 
                        sm->getHeight(),
 
26
        backgroundSurf = SDL_AllocSurface(screen->flags,
 
27
                        width,
 
28
                        height,
30
29
                        screen->format->BitsPerPixel,
31
30
                        0x00ff0000,
32
31
                        0x0000ff00,
33
32
                        0x000000ff,
34
33
                        0xff000000);
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));
38
36
}
39
37
 
40
 
CScreenSing::~CScreenSing()
41
 
{
42
 
        if(videoSurf)
43
 
            SDL_FreeSurface(videoSurf);
44
 
        if(backgroundSurf)
45
 
            SDL_FreeSurface(backgroundSurf);
46
 
            
 
38
CScreenSing::~CScreenSing() {
 
39
        if (videoSurf) SDL_FreeSurface(videoSurf);
 
40
        if (backgroundSurf) SDL_FreeSurface(backgroundSurf);
47
41
        delete video;
48
 
        delete theme;
49
42
}
50
43
 
51
 
void CScreenSing::enter( void )
52
 
{
53
 
        char buff[1024];
54
 
        CScreenManager * sm = CScreenManager::getSingletonPtr();
55
 
        CSong * song = sm->getSong();
56
 
        
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);
65
 
        } else {
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);
69
 
        }
 
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);
 
54
        }
 
55
        if (!video_ok) {
 
56
                SDL_Surface* bg = song.getBackground();
 
57
                if (bg) SDL_BlitSurface(bg, NULL, backgroundSurf, NULL);
 
58
        }
 
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;
80
 
        playOffset = 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);
 
69
        playOffset = 0.0;
 
70
        song.reset();
 
71
        audio.wait(); // Until playback starts
81
72
}
82
73
 
83
 
void CScreenSing::exit( void )
84
 
{
 
74
void CScreenSing::exit() {
85
75
        CScreenManager::getSingletonPtr()->getAudio()->stopMusic();
86
76
        video->unloadVideo();
87
77
        SDL_FillRect(videoSurf,NULL,0xffffff);
88
 
        sentence.clear();
 
78
        m_sentence.clear();
89
79
        delete lyrics;
 
80
        delete theme;
90
81
        pitchGraph.clear();
91
82
}
92
83
 
93
 
void CScreenSing::manageEvent( SDL_Event event )
94
 
{
95
 
        CScreenManager * sm = CScreenManager::getSingletonPtr();
96
 
        int keypressed;
97
 
        switch(event.type) {
98
 
                case SDL_KEYDOWN:
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 ) {
105
 
                                playOffset += 20;
106
 
                        } else if( keypressed == SDLK_MINUS ) {
107
 
                                playOffset -= 20;
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);
116
 
                        }
 
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);
 
97
                }
 
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);
117
102
        }
118
103
}
119
104
 
120
 
void CScreenSing::draw( void )
121
 
{
122
 
        CScreenManager * sm = CScreenManager::getSingletonPtr();
123
 
        CRecord * record    = sm->getRecord();
124
 
        CSong   * song      = sm->getSong();
125
 
        float freq;
126
 
        int note;
127
 
        float resFactorX = sm->getWidth()/800.;
128
 
        float resFactorY = sm->getHeight()/600.;
129
 
        float resFactorAvg = (resFactorX + resFactorY)/2.;
130
 
 
131
 
        theme->theme->clear();
132
 
 
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");
135
109
                return;
136
110
        }
137
 
 
138
 
        //record->compute();
139
 
        freq = record->getFreq();
140
 
        note = record->getNoteId();
141
 
 
142
 
 
143
 
        // draw lines across the screen
144
 
        // Theme this
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;
148
 
 
149
 
        TThemeRect linerect;
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;
157
 
        linerect.x = 0;
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);
169
 
                }
170
 
        }
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);
178
 
                        }
179
 
                }
180
 
        }
181
 
 
 
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;
 
116
        double oldfontsize;
 
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)  )
186
 
                time = 0;
187
 
        else
188
 
                time += playOffset;
189
 
 
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();
 
122
        // Update scoring
 
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();
198
 
        sentence.clear();
199
 
        sentence = lyrics->getCurrentSentence();
200
 
        if( sentence.size() && previousFirstTimestamp != sentence[0]->timestamp ) {
201
 
                previousFirstTimestamp = sentence[0]->timestamp;
202
 
                pitchGraph.clear();
203
 
        }
204
 
 
 
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 )
207
 
                video->play();
208
 
 
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());
215
138
        } else {
216
139
                sm->getVideoDriver()->drawSurface(backgroundSurf_id);
217
 
                sm->getVideoDriver()->updateSurface(backgroundSurf_id , (SDL_Surface *) NULL);
218
 
        }
219
 
        
 
140
                sm->getVideoDriver()->updateSurface(backgroundSurf_id , (SDL_Surface *) NULL);
 
141
        }
220
142
        // Compute and draw the timer and the progressbar
221
 
        {
222
 
        char dateStr[32];
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); 
228
 
        }
229
 
        //draw score            
230
 
        {
231
 
        char scoreStr[32];
232
 
        sprintf(scoreStr,"%04d",int(song->score[0].score/10)*10);
233
 
        theme->p1score.text = scoreStr;
234
 
        theme->theme->PrintText(&theme->p1score);
235
 
        }
236
 
        
 
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); 
 
147
        //draw score
 
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
238
 
        TThemeTxt tmptxt;
239
 
        {
240
 
        tmptxt = theme->timertxt;       // use timertxt as template
241
 
        tmptxt.text = record->getNoteStr(note);
242
 
        tmptxt.x=0;
243
 
        tmptxt.y=sm->getHeight();
244
 
        tmptxt.fontsize = 25;
245
 
        theme->theme->PrintText(&tmptxt);
246
 
        }
247
 
 
 
151
        {
 
152
                TThemeTxt tmptxt = theme->timertxt; // use timertxt as template
 
153
                tmptxt.text = song.scale.getNoteStr(freq);
 
154
                tmptxt.x = 600;
 
155
                tmptxt.fontsize = 25;
 
156
                theme->theme->PrintText(&tmptxt);
 
157
        }
248
158
        // compute and draw the text
249
 
        unsigned int totalBpm;
250
 
        float bpmPixelUnit;
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) {
 
165
                        pitchGraph.clear();
 
166
                        sentenceBegin = m_sentence[0].begin;
 
167
                }
 
168
                sentenceDuration = m_sentence.back().end - sentenceBegin;
 
169
                pixUnit = (m_width - 200.0 * resFactorX) / (sentenceDuration * 1.0);
254
170
        } else {
255
 
                totalBpm=0;
256
 
                bpmPixelUnit=0;
257
 
        }
258
 
        // Theme this
259
 
        TThemeRect tmprect;
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;
 
171
                pitchGraph.clear();
 
172
        }
 
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);
 
180
        }
 
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;
 
185
        // Theme this
 
186
        TThemeRect linerect;
 
187
        linerect.svg_width = m_width;
 
188
        linerect.svg_height = m_height;
 
189
        linerect.x = 0;
 
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;
 
199
        // Draw note lines
 
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;
 
203
                        if (n % 12) {
 
204
                                linerect.stroke_col.r = 0.5;
 
205
                                linerect.stroke_col.g = 0.5;
 
206
                                linerect.stroke_col.b = 0.5;
 
207
                        } else {
 
208
                                linerect.stroke_col.r = 0.8;
 
209
                                linerect.stroke_col.g = 0.3;
 
210
                                linerect.stroke_col.b = 0.8;
 
211
                        }
 
212
                        linerect.y = baseY + n * noteUnit;
 
213
                        theme->theme->DrawRect(linerect);
 
214
                }
 
215
        }
 
216
        // Theme this
 
217
        TThemeRect tmprect;
 
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;
269
 
 
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;
275
 
                else
276
 
                        waitLen = theme->tostartfg.final_height - waitLen * 5;
277
 
                
278
 
                theme->tostartfg.height = theme->tostartfg.final_height - waitLen;
279
 
                theme->theme->DrawRect(theme->tostartfg); 
280
 
        }
281
 
 
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);
285
 
 
286
 
                // if C <= timestamp < N
287
 
                if( time > ( (sentence[i]->timestamp+sentence[i]->length)  * 60 * 1000) / ( song->bpm[0].bpm * 4 ) + song->gap ) {
288
 
                        int y = noteHeight;
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 ) {
300
 
                        int y = noteHeight;
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);
310
 
                } else {
311
 
                        int y = noteHeight;
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);
324
 
                    
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);
332
 
 
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);
337
 
                        if(freq != 0.0) {
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++;
343
 
                        } else {
344
 
                                pitchGraph.renderPitch( 0.0, ((double)current + 100)/sm->getWidth());
345
 
                        }
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);
 
226
        int state = 0;
 
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;
 
236
                if (state < 2) {
 
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;
 
241
                } else {
 
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;
 
248
                                break;
 
249
                          case Note::GOLDEN:
 
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;
 
254
                                break;
 
255
                          default:
 
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;
350
260
                        }
351
 
                }
352
 
        }
353
 
        
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;
360
 
        
361
 
        if( sentencePast[0] ) {
362
 
                theme->lyricspast.text = sentencePast;
363
 
                theme->theme->PrintText(&theme->lyricspast);
364
 
        }
365
 
        
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;
373
 
 
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);
380
 
        }
381
 
        
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);
386
 
        }
387
 
 
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);
393
 
        }
394
 
 
395
 
        sm->getVideoDriver()->updateSurface(theme_id, theme->theme->getCurrent());
 
261
                }
 
262
                theme->theme->DrawRect(tmprect);
 
263
                if (state == 1) { --i; state = 2; }
 
264
        }
 
265
 
 
266
        if (!m_sentence.empty()) {
 
267
                double graphTime = (baseX + time * pixUnit) / m_width;
 
268
                if (freq == 0.0) {
 
269
                        pitchGraph.renderPitch(0.0, graphTime, 0.0);
 
270
                } else {
 
271
                        unsigned int i = 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);
 
277
                }
 
278
        }
 
279
        
 
280
        TThemeTxt tmptxt = theme->lyricspast;
 
281
        tmptxt.text = sentenceWhole;
 
282
        {
 
283
                cairo_text_extents_t extents = theme->theme->GetTextExtents(tmptxt);
 
284
                theme->lyricspast.x = (theme->lyricspast.svg_width - extents.width)/2;
 
285
        }
 
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;
 
295
        }
 
296
        theme->lyricspast.extents.x_advance = 0;
 
297
        theme->lyricshighlight.extents.x_advance= 0;
 
298
        
 
299
        if (!sentencePast.empty()) {
 
300
                theme->lyricspast.text = sentencePast;
 
301
                theme->theme->PrintText(&theme->lyricspast);
 
302
        }
 
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);
 
312
        }
 
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);
 
317
        }
 
318
 
 
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;
 
327
                }
 
328
                theme->theme->PrintText(&theme->lyricsnextsentence);
 
329
        }
 
330
 
 
331
        theme->lyricspast.fontsize = oldfontsize;
 
332
        theme->lyricshighlight.fontsize = oldfontsize;
 
333
        theme->lyricsfuture.fontsize = oldfontsize;
 
334
        theme->lyricsnextsentence.fontsize = oldfontsize;
 
335
 
 
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);
399
340
}