2004-05-31 22:42:12 +00:00
|
|
|
#ifndef NOTE_TYPES_H
|
|
|
|
|
#define NOTE_TYPES_H
|
2002-08-13 23:26:46 +00:00
|
|
|
|
2004-09-12 05:56:24 +00:00
|
|
|
struct TapNote
|
|
|
|
|
{
|
|
|
|
|
enum Type {
|
2004-10-23 23:41:49 +00:00
|
|
|
empty, // no note here
|
2004-09-12 05:56:24 +00:00
|
|
|
tap,
|
|
|
|
|
hold_head, // graded like a TAP_TAP
|
|
|
|
|
hold_tail, /* In 2sand3s mode, holds are deleted and TAP_HOLD_END is added: */
|
|
|
|
|
hold, /* In 4s mode, holds and TAP_HOLD_HEAD are deleted and TAP_HOLD is added: */
|
|
|
|
|
mine, // don't step!
|
|
|
|
|
attack,
|
2004-10-24 10:45:30 +00:00
|
|
|
autoKeysound,
|
2004-10-23 23:41:49 +00:00
|
|
|
} type;
|
2004-09-12 05:56:24 +00:00
|
|
|
enum Source {
|
|
|
|
|
original, // part of the original NoteData
|
|
|
|
|
addition, // additional note added by a transform
|
|
|
|
|
removed, // Removed taps, e.g. in Little - play keysounds here as if
|
|
|
|
|
// judged Perfect, but don't bother rendering or judging this
|
|
|
|
|
// step. Also used for when we implement auto-scratch in BM,
|
|
|
|
|
// and for if/when we do a "reduce" modifier that cancels out
|
|
|
|
|
// all but N keys on a line [useful for BM->DDR autogen, too].
|
|
|
|
|
// Removed hold body (...why?) - acts as follows:
|
|
|
|
|
// 1 - if we're using a sustained-sound gametype [Keyboardmania], and
|
|
|
|
|
// we've already hit the start of the sound (?? we put Holds Off on?)
|
|
|
|
|
// then this is triggered automatically to keep the sound going
|
|
|
|
|
// 2 - if we're NOT [anything else], we ignore this.
|
|
|
|
|
// Equivalent to all 4s aside from the first one.
|
2004-10-23 23:41:49 +00:00
|
|
|
} source;
|
2004-09-12 05:56:24 +00:00
|
|
|
|
2004-10-23 23:41:49 +00:00
|
|
|
// Only valid if type == attack.
|
|
|
|
|
CString sAttackModifiers;
|
|
|
|
|
float fAttackDurationSeconds;
|
2004-09-29 07:19:44 +00:00
|
|
|
|
2004-10-23 23:41:49 +00:00
|
|
|
bool bKeysound; // true if this note plays a keysound when hit
|
|
|
|
|
|
|
|
|
|
int iKeysoundIndex; // index into Song's vector of keysound files.
|
2004-09-29 07:19:44 +00:00
|
|
|
// Only valid if bKeysound.
|
|
|
|
|
|
2004-10-23 23:41:49 +00:00
|
|
|
TapNote() {}
|
|
|
|
|
TapNote(
|
2004-09-29 07:19:44 +00:00
|
|
|
Type type_,
|
|
|
|
|
Source source_,
|
2004-10-23 23:41:49 +00:00
|
|
|
CString sAttackModifiers_,
|
|
|
|
|
float fAttackDurationSeconds_,
|
2004-09-29 07:19:44 +00:00
|
|
|
bool bKeysound_,
|
2004-10-23 23:41:49 +00:00
|
|
|
int iKeysoundIndex_ )
|
2004-09-12 05:56:24 +00:00
|
|
|
{
|
|
|
|
|
type = type_;
|
|
|
|
|
source = source_;
|
2004-10-23 23:41:49 +00:00
|
|
|
sAttackModifiers = sAttackModifiers_;
|
|
|
|
|
fAttackDurationSeconds = fAttackDurationSeconds_;
|
2004-09-29 07:19:44 +00:00
|
|
|
bKeysound = bKeysound_;
|
2004-10-23 23:41:49 +00:00
|
|
|
iKeysoundIndex = iKeysoundIndex_;
|
2004-09-12 05:56:24 +00:00
|
|
|
}
|
2004-10-24 10:20:24 +00:00
|
|
|
bool operator==( const TapNote &other ) const
|
2004-09-29 06:43:57 +00:00
|
|
|
{
|
|
|
|
|
#define COMPARE(x) if(x!=other.x) return false;
|
|
|
|
|
COMPARE(type);
|
|
|
|
|
COMPARE(source);
|
2004-10-23 23:41:49 +00:00
|
|
|
COMPARE(sAttackModifiers);
|
|
|
|
|
COMPARE(fAttackDurationSeconds);
|
2004-09-29 07:19:44 +00:00
|
|
|
COMPARE(bKeysound);
|
2004-10-23 23:41:49 +00:00
|
|
|
COMPARE(iKeysoundIndex);
|
2004-09-29 06:43:57 +00:00
|
|
|
#undef COMPARE
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2004-09-12 05:56:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const unsigned MAX_NUM_ATTACKS = 2*2*2; // 3 bits to hold the attack index currently
|
|
|
|
|
|
2004-10-24 10:20:24 +00:00
|
|
|
extern TapNote TAP_EMPTY; // '0'
|
|
|
|
|
extern TapNote TAP_ORIGINAL_TAP; // '1'
|
|
|
|
|
extern TapNote TAP_ORIGINAL_HOLD_HEAD; // '2'
|
|
|
|
|
extern TapNote TAP_ORIGINAL_HOLD_TAIL; // '3'
|
|
|
|
|
extern TapNote TAP_ORIGINAL_HOLD; // '4'
|
|
|
|
|
extern TapNote TAP_ORIGINAL_MINE; // 'M'
|
|
|
|
|
extern TapNote TAP_ORIGINAL_ATTACK; // 'A'
|
2004-10-24 10:45:30 +00:00
|
|
|
extern TapNote TAP_ORIGINAL_AUTO_KEYSOUND; // 'K'
|
2004-09-12 05:56:24 +00:00
|
|
|
extern TapNote TAP_ADDITION_TAP;
|
|
|
|
|
extern TapNote TAP_ADDITION_MINE;
|
|
|
|
|
|
|
|
|
|
// TODO: Don't have a hard-coded track limit.
|
2004-09-25 07:59:56 +00:00
|
|
|
const int MAX_NOTE_TRACKS = 16;
|
2002-08-13 23:26:46 +00:00
|
|
|
|
|
|
|
|
const int BEATS_PER_MEASURE = 4;
|
2003-11-03 08:44:49 +00:00
|
|
|
const int ROWS_PER_BEAT = 48; // It is important that this number is evenly divisible by 2, 3, and 4.
|
2002-08-23 20:18:29 +00:00
|
|
|
const int ROWS_PER_MEASURE = ROWS_PER_BEAT * BEATS_PER_MEASURE;
|
2002-08-13 23:26:46 +00:00
|
|
|
|
|
|
|
|
enum NoteType
|
|
|
|
|
{
|
2002-08-23 20:18:29 +00:00
|
|
|
NOTE_TYPE_4TH, // quarter note
|
|
|
|
|
NOTE_TYPE_8TH, // eighth note
|
|
|
|
|
NOTE_TYPE_12TH, // triplet
|
|
|
|
|
NOTE_TYPE_16TH, // sixteenth note
|
2003-11-03 08:44:49 +00:00
|
|
|
NOTE_TYPE_24TH, // twenty-fourth note
|
2002-09-11 04:49:07 +00:00
|
|
|
NOTE_TYPE_32ND, // thirty-second note
|
2003-11-16 09:34:49 +00:00
|
|
|
|
|
|
|
|
// Why is this high of resolution needed? It's breaking NoteSkins
|
|
|
|
|
// with note-coloring, and the extra resolution will take up more
|
|
|
|
|
// memory. Does any game actually use this? -Chris
|
|
|
|
|
|
2003-11-03 08:44:49 +00:00
|
|
|
// MD 11/02/03 - added finer divisions
|
|
|
|
|
NOTE_TYPE_48TH, // forty-eighth note
|
|
|
|
|
NOTE_TYPE_64TH, // sixty-fourth note
|
2003-11-13 07:40:49 +00:00
|
|
|
// Not having this triggers asserts all over the place. Go figure.
|
|
|
|
|
NOTE_TYPE_192ND,
|
2002-08-13 23:26:46 +00:00
|
|
|
NUM_NOTE_TYPES,
|
2002-08-23 20:18:29 +00:00
|
|
|
NOTE_TYPE_INVALID
|
2002-08-13 23:26:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
float NoteTypeToBeat( NoteType nt );
|
2004-10-24 00:17:15 +00:00
|
|
|
NoteType GetNoteType( int row );
|
2003-02-05 03:53:57 +00:00
|
|
|
NoteType BeatToNoteType( float fBeat );
|
2004-10-24 00:17:15 +00:00
|
|
|
bool IsNoteOfType( int row, NoteType t );
|
2003-02-06 07:32:57 +00:00
|
|
|
CString NoteTypeToString( NoteType nt );
|
2002-08-13 23:26:46 +00:00
|
|
|
|
2003-12-16 04:00:39 +00:00
|
|
|
inline int BeatToNoteRow( float fBeatNum ) { return int( fBeatNum * ROWS_PER_BEAT + 0.5f); }; // round
|
|
|
|
|
inline int BeatToNoteRowNotRounded( float fBeatNum ) { return (int)( fBeatNum * ROWS_PER_BEAT ); };
|
|
|
|
|
inline float NoteRowToBeat( float fNoteIndex ) { return fNoteIndex / (float)ROWS_PER_BEAT; };
|
2004-10-24 00:17:15 +00:00
|
|
|
inline float NoteRowToBeat( int row ) { return NoteRowToBeat( (float)row ); };
|
2003-12-16 04:00:39 +00:00
|
|
|
|
2002-08-13 23:26:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
struct HoldNote
|
|
|
|
|
{
|
2003-12-16 04:00:39 +00:00
|
|
|
HoldNote( int t, int s, int e ) { iTrack=t; iStartRow=s; iEndRow=e; }
|
|
|
|
|
bool RowIsInRange( int row ) const { return iStartRow <= row && row <= iEndRow; }
|
|
|
|
|
bool RangeOverlaps( int start, int end ) const
|
|
|
|
|
{
|
2004-04-29 00:33:09 +00:00
|
|
|
/* If the range doesn't overlap us, then start and end are either both before
|
|
|
|
|
* us or both after us. */
|
|
|
|
|
return !( (start < iStartRow && end < iStartRow) ||
|
|
|
|
|
(start > iEndRow && end > iEndRow) );
|
2003-12-16 04:00:39 +00:00
|
|
|
}
|
|
|
|
|
bool RangeOverlaps( const HoldNote &hn ) const { return RangeOverlaps(hn.iStartRow, hn.iEndRow); }
|
|
|
|
|
bool RangeInside( int start, int end ) const { return iStartRow <= start && end <= iEndRow; }
|
2004-04-29 00:33:09 +00:00
|
|
|
bool ContainedByRange( int start, int end ) const { return start <= iStartRow && iEndRow <= end; }
|
2003-12-16 04:00:39 +00:00
|
|
|
|
|
|
|
|
float GetStartBeat() const { return NoteRowToBeat( iStartRow ); }
|
|
|
|
|
float GetEndBeat() const { return NoteRowToBeat( iEndRow ); }
|
2004-04-29 00:33:09 +00:00
|
|
|
|
|
|
|
|
/* Invariant: iStartRow <= iEndRow */
|
2003-12-16 04:00:39 +00:00
|
|
|
int iStartRow;
|
|
|
|
|
int iEndRow;
|
2004-04-29 00:33:09 +00:00
|
|
|
int iTrack;
|
2002-08-13 23:26:46 +00:00
|
|
|
};
|
|
|
|
|
|
2002-11-16 08:07:38 +00:00
|
|
|
#endif
|
2004-05-31 22:42:12 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* (c) 2001-2004 Chris Danford, Glenn Maynard
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
|
|
|
|
* whom the Software is furnished to do so, provided that the above
|
|
|
|
|
* copyright notice(s) and this permission notice appear in all copies of
|
|
|
|
|
* the Software and that both the above copyright notice(s) and this
|
|
|
|
|
* permission notice appear in supporting documentation.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
|
|
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
|
|
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
|
|
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
|
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
*/
|