//------------------------------------------------------------------------- // Filename: player.cc // Version: $Id: player.cc,v 1.1.4.3 1999/06/09 10:14:05 erik Exp $ // Copyright: Copyright (C) 1999, Erik Mouw (J.A.K.Mouw@its.tudelft.nl) // Author: Erik Mouw // Description: MIDI player // Created at: Sun Mar 28 23:23:17 1999 // Modified by: Erik Mouw // Modified at: Wed May 26 17:36:32 1999 //------------------------------------------------------------------------- // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // #ident "$Id: player.cc,v 1.1.4.3 1999/06/09 10:14:05 erik Exp $" #ifdef HAVE_CONFIG_H # include #endif #if STDC_HEADERS # include #else # ifdef HAVE_MALLOC_H # include # else # ifndef NULL # define NULL ((void *)0) # endif # endif #endif #if (MUSICA_DEBUG || TIMING_DEBUG) # include #endif #include #include #include "player.hh" #include "sequence.hh" #include "mididevice.hh" bool midiPlayer::setSequence(midiSequence *theSequence) { // sanity check assert(theSequence != 0); playing = false; startPlaying = false; sequence = theSequence; sequence->rewind(); setDivision(sequence->getDivision()); return(true); } bool midiPlayer::setDevice(midiDevice *theDevice) { // sanity check assert(theDevice != 0); device = theDevice; return(true); } void midiPlayer::setDivision(int n) { if(n > 0) division = n; else division = 120; // FIXME: this is NOT correct, but a safe default version #ifdef MUSICA_DEBUG cerr<< __PRETTY_FUNCTION__<< ": division = "<< division<< endl; #endif // FIXME: this is just a hack! I don't really understand // how to use the division thingy; it works correct for division == 120 // but fails for division > 120 if(division > 120) { division *= 2; #ifdef MUSICA_DEBUG cerr<< __PRETTY_FUNCTION__<< ": using division hack: division = "<< division<< endl; #endif } } void midiPlayer::sequenceNumber(int n) { number = n; } void midiPlayer::endOfTrack(void) { } void midiPlayer::setTempo(long int t) { tempo = t; #ifdef MUSICA_DEBUG cerr<< __PRETTY_FUNCTION__<< ": tempo = "<< t<< endl; #endif } void midiPlayer::smpteOffset(int h, int m, int s, int f, int fr) { hours = h; minutes = m; seconds = s; frames = f; fraction = fr; } void midiPlayer::timeSignature(int n, int d, int c, int b) { numerator = n; denominator = d; clocks = c; bb = b; } void midiPlayer::keySignature(int k, int s) { key = k; signature = s; } void midiPlayer::setRelativeTempo(int value) { if(value == 0) { relTempoNumerator = relTempoDenominator = 10; } else if(value > 0) { relTempoNumerator = 10; relTempoDenominator = value + 10; } else // value < 0 { relTempoNumerator = -value + 10; relTempoDenominator = 10; } } void midiPlayer::setFastForwardSpeed(double value) { #ifdef MUSICA_DEBUG cerr<< __PRETTY_FUNCTION__<< ": value = "<< value<< endl; #endif // reasonable range if((value >= 2.0) && (value <= 10.0)) ffwdSpeed = value; } double midiPlayer::getFastForwardSpeed(void) { #ifdef MUSICA_DEBUG cerr<< __PRETTY_FUNCTION__<< endl; #endif return(ffwdSpeed); } void midiPlayer::rewind(void) { #ifdef MUSICA_DEBUG cerr<< __PRETTY_FUNCTION__<< endl; #endif playing = false; sequence->rewind(); } void midiPlayer::play(void) { #ifdef MUSICA_DEBUG cerr<< __PRETTY_FUNCTION__<< endl; #endif playing = true; startPlaying = true; } void midiPlayer::fastForward(bool value) { #ifdef MUSICA_DEBUG cerr<< __PRETTY_FUNCTION__<< ": value = "<< (value ? "true" : "false")<< endl; #endif doFastForward = value; } void midiPlayer::stop(void) { #ifdef MUSICA_DEBUG cerr<< __PRETTY_FUNCTION__<< endl; #endif playing = false; } // get deltatime, multiply with correct amount to get real time long int midiPlayer::nextNote(void) { double numerator, denominator; // numerator = (double)current->deltaTime * // (double)tempo * // (double)relTempoNumerator; numerator = (double)sequence->getDeltaTime() * (double)tempo * (double)relTempoNumerator; denominator = (double)division * (double)relTempoDenominator; if(doFastForward == true) denominator *= ffwdSpeed; #ifdef MUSICA_DEBUG if(numerator < 0.0) cerr<< __PRETTY_FUNCTION__<< ": numerator < 0.0"<< endl; #endif return((long int) rint(numerator / denominator)); } // play midi sequence long int midiPlayer::doPlay(long int currentTime) { if(playing == false) return(-1L); if((sequence == 0) || (sequence->getDeltaTime() < 0L)) { #ifdef MUSICA_DEBUG cerr<< __PRETTY_FUNCTION__<< ": sequence == 0 || deltaTime < 0"<< endl; #endif stop(); return(-1L); } if(startPlaying == true) { startTime = currentTime; lastEventTime = currentTime; nextEventTime = lastEventTime + nextNote(); startPlaying = false; } // play all events that we had to play until now while(currentTime >= nextEventTime) { #ifdef TIMING_DEBUG cout << "last event time = "<< lastEventTime<< ", current time = "<< currentTime<< ", next event time = "<< nextEventTime<< endl; #endif sequence->play(device, this); lastEventTime = nextEventTime; if(sequence->getDeltaTime() >= 0L) { // get new deltaT nextEventTime = lastEventTime + nextNote(); } else { // no more events to play #ifdef MUSICA_DEBUG cerr<< __PRETTY_FUNCTION__<< ": deltaTime < 0L"<< endl; #endif stop(); return(-1L); } } // return number of microseconds before next event return(nextEventTime - currentTime); }