diff --git a/stepmania/src/NotesLoaderMidi.cpp b/stepmania/src/NotesLoaderMidi.cpp index e03ae62a2f..18dde11b6a 100644 --- a/stepmania/src/NotesLoaderMidi.cpp +++ b/stepmania/src/NotesLoaderMidi.cpp @@ -137,6 +137,12 @@ public: double tickSeconds; }; std::vector tempoEvents_; + struct TimeSignatureChange { + unsigned long count; + unsigned long numerator; + unsigned long denominator; + }; + std::vector timeSignatureEvents_; std::vector trackCounters_; std::vector trackTempoIndex_; @@ -176,9 +182,9 @@ void MidiFileIn :: Load( RString fileName ) char chunkType[4]; int32_t length; if( !file_.Read( chunkType, 4 ) ) - goto error; + FAIL_M( "NotesLoaderMidi" ); if( !file_.Read( &length, 4 ) ) - goto error; + FAIL_M( "NotesLoaderMidi" ); length = Swap32BE( length ); if( strncmp( chunkType, "MThd", 4 ) || ( length != 6 ) ) { @@ -188,7 +194,7 @@ void MidiFileIn :: Load( RString fileName ) // Read the MIDI file format. int16_t data; if( !file_.Read( &data, 2 ) ) - goto error; + FAIL_M( "NotesLoaderMidi" ); data = Swap16BE( data ); if( data < 0 || data > 2 ) { @@ -198,7 +204,7 @@ void MidiFileIn :: Load( RString fileName ) // Read the number of tracks. if( !file_.Read( &data, 2 ) ) - goto error; + FAIL_M( "NotesLoaderMidi" ); data = Swap16BE( data ); if( format_ == 0 && data != 1 ) { @@ -208,7 +214,7 @@ void MidiFileIn :: Load( RString fileName ) // Read the beat division. if( !file_.Read( &data, 2 ) ) - goto error; + FAIL_M( "NotesLoaderMidi" ); data = Swap16BE( data ); division_ = (int)data; double tickrate; @@ -235,11 +241,11 @@ void MidiFileIn :: Load( RString fileName ) for( unsigned int i=0; i tempoEvents_.back().count ) - tempoEvents_.push_back( tempoEvent ); - else - tempoEvents_.back() = tempoEvent; - } - count += getNextEvent( &event, 0 ); + TempoChange tempoEvent; + tempoEvent.count = count; + unsigned long value = ( event[3] << 16 ) + ( event[4] << 8 ) + event[5]; + tempoEvent.tickSeconds = (double) (0.000001 * value / tickrate); + if( count > tempoEvents_.back().count ) + tempoEvents_.push_back( tempoEvent ); + else + tempoEvents_.back() = tempoEvent; + } + + if( ( event.size() == 7 ) && ( event[0] == 0xff ) && + ( event[1] == 0x58 ) && ( event[2] == 0x04 ) ) + { + TimeSignatureChange timeSignatureEvent; + timeSignatureEvent.count = count; + timeSignatureEvent.numerator = event[3]; + timeSignatureEvent.denominator = (int)pow( 2, (int)event[4] ); + //unsigned long metronome = event[5]; // not currently used + //unsigned long u32nds = event[6]; // not currently used + if( count > timeSignatureEvents_.back().count ) + timeSignatureEvents_.push_back( timeSignatureEvent ); + else + timeSignatureEvents_.back() = timeSignatureEvent; + } + + count += getNextEvent( &event, 0 ); } rewindTrack( 0 ); for( unsigned int i=0; i *event, uns // Read the event delta time. file_.Seek( trackPointers_[track] ); if( !readVariableLength( &ticks ) ) - goto error; + FAIL_M( "NotesLoaderMidi" ); // Parse the event stream to determine the event length. unsigned char c; if( !file_.Read( (char *)&c, 1 ) ) - goto error; + FAIL_M( "NotesLoaderMidi" ); switch( c ) { case 0xFF: // A Meta-Event unsigned long position; - trackStatus_[track] = 0; + + // RealTime Category messages (ie, Status of 0xF8 to 0xFF) do not affect running status + event->push_back( c ); if( !file_.Read( (char *)&c, 1 ) ) - goto error; + FAIL_M( "NotesLoaderMidi" ); event->push_back( c ); if( format_ != 1 && ( c == 0x51 ) ) isTempoEvent = true; position = file_.Tell(); if( !readVariableLength( &bytes ) ) - goto error; + FAIL_M( "NotesLoaderMidi" ); bytes += ( (unsigned long)file_.Tell() - position ); file_.Seek( position ); break; @@ -408,7 +441,7 @@ unsigned long MidiFileIn :: getNextEvent( std::vector *event, uns event->push_back( c ); position = file_.Tell(); if( !readVariableLength( &bytes ) ) - goto error; + FAIL_M( "NotesLoaderMidi" ); bytes += ( (unsigned long)file_.Tell() - position ); file_.Seek( position ); break; @@ -417,7 +450,7 @@ unsigned long MidiFileIn :: getNextEvent( std::vector *event, uns if( c & 0x80 ) // MIDI status byte { if( c > 0xF0 ) - goto error; + FAIL_M( "NotesLoaderMidi" ); trackStatus_[track] = c; event->push_back( c ); c &= 0xF0; @@ -436,7 +469,7 @@ unsigned long MidiFileIn :: getNextEvent( std::vector *event, uns } else { - goto error; + FAIL_M( "NotesLoaderMidi" ); } break; @@ -446,7 +479,7 @@ unsigned long MidiFileIn :: getNextEvent( std::vector *event, uns for( unsigned long i=0; ipush_back( c ); } @@ -477,10 +510,6 @@ unsigned long MidiFileIn :: getNextEvent( std::vector *event, uns trackPointers_[track] = file_.Tell(); return ticks; - -error: - FAIL_M( "MidiFileIn::getNextEvent: file read error!" ); - return 0; } unsigned long MidiFileIn :: getNextMidiEvent( std::vector *midiEvent, unsigned int track ) @@ -632,7 +661,17 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut ) double fSecondsPerBeat = (iter->tickSeconds * GUITAR_MIDI_COUNTS_PER_BEAT); bpmSeg.m_fBPS = 1 / fSecondsPerBeat; - songOut.AddBPMSegment( bpmSeg ); + songOut.m_Timing.AddBPMSegment( bpmSeg ); + } + + FOREACH_CONST( MidiFileIn::TimeSignatureChange, midi.timeSignatureEvents_, iter ) + { + TimeSignatureSegment seg; + seg.m_iStartRow = MidiCountToNoteRow( iter->count ); + seg.m_iNumerator = iter->numerator; + seg.m_iDenominator = iter->denominator; + + songOut.m_Timing.AddTimeSignatureSegment( seg ); } @@ -644,7 +683,7 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut ) { std::vector event; - int iTrack = 1; // this track should be named "T1 GEMS" + int iTrack = 1; // this track should be named "T1 GEMS" or "PART GUITAR" unsigned long count = midi.getNextEvent( &event, iTrack ); double fSeconds = midi.getTickSeconds( iTrack ); while( event.size() ) @@ -671,6 +710,7 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut ) if( NoteNumberToDifficultyAndNoteNumberType( uNoteNumber, gd, nnt ) ) { MidiEvent event = { count, midiEventType }; + //float fBeat = NoteRowToBeat( MidiCountToNoteRow(count) ); vMidiEvent[gd][nnt].push_back( event ); } } @@ -723,6 +763,7 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut ) */ MidiEventType midiEventType = iter->midiEventType; long count = iter->count; + //float fBeat = NoteRowToBeat( MidiCountToNoteRow(count) ); bool bNoteHandled = false; long length = count - countOfLastNote;