summaryrefslogtreecommitdiff
path: root/vfg/src/music.h
blob: f9317de801e8fed22628a552b41ee28aa71d49a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#pragma once

#include "ofMain.h"
#include "ofxXmlSettings.h"
#include "Puppet.h"

//event times are absolute integer milliseconds
//---------------------------------------------------------------------------------------------------------------------------------------------
class levelscore {
	public:
		void load(string filename) {
			ofxXmlSettings XML;
			if( !XML.loadFile(filename) ){
				printf("unable to load %s check data/ folder\n",filename.c_str());
			}else{
				if(XML.pushTag("VFxmas")) {
					for (int i=0;i<XML.getNumTags("Level");i++) {
						levels[XML.getAttribute("Level", "Time",0,i)]=XML.getAttribute("Level", "Lives",0,i);
					}
					printf("processed %s: %i difficulty levels \n",filename.c_str(),levels.size());
				}
			}
		}
		int getLives(int time) {
			map<int,int>::iterator iter;
			int lives=0;
			for (iter = levels.begin(); iter != levels.end(); ++iter) {
				if (iter->first<=time) lives=iter->second;
				else break;
			}
			return lives;
		}
		int getLevel(int time) {
			map<int,int>::iterator iter;
			int level=-1;
			for (iter = levels.begin(); iter != levels.end(); ++iter) {
				if (iter->first<=time) level++;
				else break;
			}
			return level;
		}
		int getLowerBound(int level) {
			map<int,int>::iterator iter=levels.begin();
			int bound=0;
			for (int i=0;i<=level;i++) {
				bound=iter->first;
				iter++;
			}
			return bound;
		}
	private:
		map<int,int> levels;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class note {
	public:
		note(int n,int v,int d=0) {
			num=n;
			velocity=v;
			duration=d;
		}
		int num;
		int velocity;
		int duration; //may be needed another time?
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class flake: public note, public Puppet {
	public:
		flake(int n,int v,int d=0) : note(n,v,d) { activated=false; }
		Puppet puppet;
		bool activated;
		void activate() {
			activated=true;
			puppet.play("shatter");
		}
		void draw(float x, float y) {
			if (!activated||puppet.isPlaying()) puppet.draw(x,y);
		}
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class lyric {
	public:
		lyric(string s,int d) {
			text=s;
			duration=d;
		}
		string text;
		int duration;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class score {
	//basics of timelime
	public:
		long startTime;
		void start() { startTime=ofGetElapsedTimeMillis(); }
		void start(int _st) { startTime=_st; }
		ofxXmlSettings XML;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class lyricscore: public score {
	//draws lyrics to screen for a certain time
	public:
        lyricscore() {
            font.loadFont("verdana.ttf", 30, true, true);
            font.setLineHeight(34.0f);
            font.setLetterSpacing(1.035);
            ypos=(int)(((float)ofGetHeight())*0.97f); //set lyric position
            fadeout=500; //ms
        }
		void load(string filename) {
			if( !XML.loadFile(filename) ){
				printf("unable to load %s check data/ folder\n",filename.c_str());
			}else{
				int multiplier=1000/XML.getAttribute("VFxmas", "timebase",0,0);
				if(XML.pushTag("VFxmas")) {
					for (int i=0;i<XML.getNumTags("Lyric");i++) {
						int in=XML.getAttribute("Lyric", "In",0,i)*multiplier;
						lyrics[in]=new lyric(XML.getValue("Lyric","",i),(XML.getAttribute("Lyric", "Out",0,i)*multiplier)-in);
					}
					printf("processed %s: %i lyrics \n",filename.c_str(),lyrics.size());
				}

			}
		}
		void draw();
	private:
		map<int,lyric*> lyrics;
		ofTrueTypeFont	font;
		int ypos;
		int fadeout;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class musicscore: public score {
	//draws notes to screen for a certain time and certain parameters, checks when they become ready
	public:
		musicscore();
		void parseMidi(string filename);
		void setTimeframe(int millis);
		void setNowpoint(float pct);
		void drawNotes(levelscore *levels);
		void drawFlakes(levelscore *levels);
		void playerControl(int key,int threshold);
		void makeFlakes(int threshStart,int threshEnd);

		int missedFlakes;
		int missedNote;
		bool missedLast;
		bool perfect;

	private:
		map<int,note*> notes;
		map<int,flake*> flakes;
		map<int,flake*>::iterator missedFlake;
		int timeframe;
		float nowpoint;

		vector<Puppet> snowflakes;

};
//---------------------------------------------------------------------------------------------------------------------------------------------
class song {
	public:
		song(string backfile,string melfile,string musfile,string lyricfile,string levelfile);
		void play();
		void stop();
		void preRoll(long preroll);
		void setTimeframe(int millis);
		void setFlakeThresh(int tS,int tE);
		void setKeythresh(int millis);
		void drawNotes();
		void draw();
		int missedNote();
		bool isPlaying;
		void playerControl(int key);
	private:
		ofSoundPlayer backing;
		ofSoundPlayer melody;
		lyricscore lyrics;
		musicscore notes;
		levelscore levels;
		long startTime;
		bool isPreroll;

		int fThreshStart,fThreshEnd,keyThresh;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
/*
Game
Animation & Sound Demo – NK to overlay latest version of Deck the Halls on 10 second animated sequence by COB Wednesday 7th November for visual and aural aesthetic sign-off. RM to send through latest version of Deck the Halls today (6th November).
Game Development – TR presented initial demo today. Usability looks good. NK to provide first suite of graphics by COB Wednesday 7th November.
Latency Test – TR and GK to perform end-to-end latency test next Monday 12th November once Vodafone have connected the 1800 number to the 01 number. Any issues noted in the testing to be flagged to BL.
Game Over – Players who miss a certain amount of notes in a row will be kicked out of the game early. The number of notes that can be missed in a row will decrease as the game goes on (subject to testing and tweaking):

Stage 1 – N/A (it will not be possible to be kicked out in Stage 1)
Stage 2 – 5 notes missed will mean Game Over
Stage 3 – 4 notes missed will mean Game Over
Stage 4 – 3 notes missed will mean Game Over

Scoring – Scoring will be based on the level of the game you achieve. There will be 4 scoring brackets (subject to testing and tweaking):

Scoring Bracket 1 - Those who make it to Level 2 (see above - it's not possible to be kicked out in Level 1)
Scoring Bracket 2 – Those who make it to Level 3
Scoring Bracket 3 – Those who make it to Level 4
Scoring Bracket 4 – Those who don't miss any notes in Level 4

*/