diff options
Diffstat (limited to 'drumgizmo/input')
| -rw-r--r-- | drumgizmo/input/midifile/midifile.cc | 451 | 
1 files changed, 257 insertions, 194 deletions
| diff --git a/drumgizmo/input/midifile/midifile.cc b/drumgizmo/input/midifile/midifile.cc index d73d382..54865ef 100644 --- a/drumgizmo/input/midifile/midifile.cc +++ b/drumgizmo/input/midifile/midifile.cc @@ -38,91 +38,154 @@  class MidiFile {  public: -  MidiFile(); -  ~MidiFile() {} +	MidiFile() = default; +	~MidiFile() = default; -  bool init(int instruments, char *inames[]); +	bool init(int instruments, char *inames[]); -  void setParm(std::string parm, std::string value); +	void setParm(std::string parm, std::string value); -  bool start(); -  void stop(); -   -  void pre(); -  event_t *run(size_t pos, size_t len, size_t *nevents); -  void post(); +	bool start(); +	void stop(); + +	void pre(); +	event_t *run(size_t pos, size_t len, size_t *nevents); +	void post();  private: -  smf_t *smf; -  smf_event_t *cur_event; - -  MidiMapper mmap; - -  // Parameters -  std::string filename; -  float speed; -  int track; -  std::string midimapfile; -  bool loop; -  double offset; +	smf_t *smf{nullptr}; +	smf_event_t *cur_event{nullptr}; + +	MidiMapper mmap; + +	// Parameters +	std::string filename; +	float speed{1.0}; +	int track{-1}; // -1 is omni ie. all tracks +	std::string midimapfile; +	bool loop{false}; +	double offset{0}; +	double tempoOverrideBpm{-1}; // -1 is disabled.  }; -MidiFile::MidiFile() -{ - cur_event = NULL; - smf = NULL; -  - speed = 1.0; - track = -1; // -1 is OMNI/all tracks - loop = false; - offset = 0; -} -   bool MidiFile::init(int instruments, char *inames[])  { -  if(filename == "") { -    fprintf(stderr, "Missing midifile argument 'file'\n"); -    return false; -  } - -  if(midimapfile == "") { -    fprintf(stderr, "Missing midimapfile argument 'midimap'.\n"); -    return false; -  } - -  smf = smf_load(filename.c_str()); - -  if(!smf) { -    fprintf(stderr, "Could not open midifile '%s'.\n", filename.c_str()); -    return false; -  } - -  MidiMapParser p(midimapfile); -  if(p.parse()) { -    fprintf(stderr, "Could not parse midimapfile '%s'.\n", midimapfile.c_str()); -    return false; -  } -  mmap.midimap = p.midimap; - -  for(int i = 0; i < instruments; i++) { -    mmap.instrmap[inames[i]] = i; -  } - -  return true; +	if(filename == "") +	{ +		fprintf(stderr, "Missing midifile argument 'file'\n"); +		return false; +	} + +	if(midimapfile == "") +	{ +		fprintf(stderr, "Missing midimapfile argument 'midimap'.\n"); +		return false; +	} + +	smf = smf_load(filename.c_str()); + +	if(!smf) +	{ +		fprintf(stderr, "Could not open midifile '%s'.\n", filename.c_str()); +		return false; +	} + +	// Override tempo is supplied by the user +	if(tempoOverrideBpm > 0) +	{ +		// Tempo change event format: +		// FF 51 03 tttttt - Set Tempo, in microseconds per MIDI quarter-note +		unsigned char midiData[] = { 0xff, 0x51, 0x03, 0, 0, 0 }; + +		unsigned int usecPerMinute = 60000000; +		unsigned int mpqn = usecPerMinute / tempoOverrideBpm; +		midiData[3] = (mpqn >> 0) & 0xff; +		midiData[4] = (mpqn >> 8) & 0xff; +		midiData[5] = (mpqn >> 16) & 0xff; + +		smf_event_t* tempoChangeEvent = +			smf_event_new_from_pointer(midiData, sizeof(midiData)); + +		while(true) +		{ +			smf_event_t* event = smf_peek_next_event(smf); + +			// Skip all initial tempo events. +			if((!smf_event_is_metadata(event)) && +			   (event->midi_buffer[1] == 0x51) && (event->midi_buffer[1] == 0x58)) +			//if(smf_event_is_tempo_change_or_time_signature(event)) // only in latest smf +			{ +				smf_skip_next_event(smf); +			} +			else +			{ +				// No more tempo change event; stop searching. +				break; +			} +		} + +		// Add tempo change event to all tracks. +		smf_track_t *track; +		unsigned int trackNumber = 1; +		while((track = smf_get_track_by_number(smf, trackNumber))) +		{ +			smf_track_add_event_seconds(track, tempoChangeEvent, 0); +			++trackNumber; +		} +	} + +	MidiMapParser p(midimapfile); +	if(p.parse()) +	{ +		fprintf(stderr, "Could not parse midimapfile '%s'.\n", midimapfile.c_str()); +		return false; +	} +	mmap.midimap = p.midimap; + +	for(int i = 0; i < instruments; ++i) +	{ +		mmap.instrmap[inames[i]] = i; +	} + +	return true;  }  void MidiFile::setParm(std::string parm, std::string value)  { -  if(parm == "file") filename = value; -  if(parm == "speed") speed = atof(value.c_str()); -  if(parm == "track") track = atoi(value.c_str()); -  if(parm == "midimap") midimapfile = value; -  if(parm == "loop") loop = true; +	if(parm == "file") +	{ +		filename = value; +	} + +	if(parm == "speed") +	{ +		speed = atof(value.c_str()); +	} + +	if(parm == "track") +	{ +		track = atoi(value.c_str()); +	} + +	if(parm == "midimap") +	{ +		midimapfile = value; +	} + +	if(parm == "loop") +	{ +		loop = true; +	} + +	if(parm == "tempo") +	{ +		tempoOverrideBpm = atof(value.c_str()); +	}  }  bool MidiFile::start()  { -  return true; +	return true;  }  void MidiFile::stop() @@ -135,63 +198,80 @@ void MidiFile::pre()  event_t *MidiFile::run(size_t pos, size_t len, size_t *nevents)  { -  event_t *evs = NULL; -  size_t nevs = 0; - -  double cur_max_time = (double)(pos + len) / (44100.0 / speed); -  cur_max_time -= offset; -  //  double cur_min_time = (double)(pos) / (44100.0 / speed); - -  if(!cur_event) cur_event = smf_get_next_event(smf); - -  while(cur_event && cur_event->time_seconds < cur_max_time) { -    if(!smf_event_is_metadata(cur_event)) { -      if( (cur_event->midi_buffer_length == 3) && -          ((cur_event->midi_buffer[0] & NOTE_ON) == NOTE_ON) && -          (track == -1 || cur_event->track_number == track) && -          cur_event->midi_buffer[2] > 0) { -         -        if(evs == NULL) evs = (event_t *)malloc(sizeof(event_t) * 1000); - -        int key = cur_event->midi_buffer[1]; -        int velocity = cur_event->midi_buffer[2]; - -        evs[nevs].type = TYPE_ONSET; -        size_t evpos = cur_event->time_seconds * (44100.0 / speed); -        evs[nevs].offset = evpos - pos; - -        int i = mmap.lookup(key); -        if(i != -1) { -          evs[nevs].instrument = i; -          evs[nevs].velocity = velocity / 127.0; -         -          nevs++; -          if(nevs > 999) { -            fprintf(stderr, "PANIC!\n"); -            break; -          } -        } -      } -    } -     -    cur_event = smf_get_next_event(smf); -  } - -  if(!cur_event) { -    if(loop) { -       smf_rewind(smf); -       offset += cur_max_time; -    } else { -      if(evs == NULL) evs = (event_t *)malloc(sizeof(event_t) * 1000); -      evs[nevs].type = TYPE_STOP; -      evs[nevs].offset = len - 1; -      nevs++; -    } -  } - -  *nevents = nevs; - -  return evs; +	event_t *evs = nullptr; +	size_t nevs = 0; + +	double cur_max_time = (double)(pos + len) / (44100.0 / speed); +	cur_max_time -= offset; +	//  double cur_min_time = (double)(pos) / (44100.0 / speed); + +	if(!cur_event) +	{ +		cur_event = smf_get_next_event(smf); +	} + +	while(cur_event && cur_event->time_seconds < cur_max_time) +	{ +		if(!smf_event_is_metadata(cur_event)) +		{ +			if( (cur_event->midi_buffer_length == 3) && +			    ((cur_event->midi_buffer[0] & NOTE_ON) == NOTE_ON) && +			    (track == -1 || cur_event->track_number == track) && +			    cur_event->midi_buffer[2] > 0) +			{ +				if(evs == nullptr) +				{ +					evs = (event_t *)malloc(sizeof(event_t) * 1000); +				} + +				int key = cur_event->midi_buffer[1]; +				int velocity = cur_event->midi_buffer[2]; + +				evs[nevs].type = TYPE_ONSET; +				size_t evpos = cur_event->time_seconds * (44100.0 / speed); +				evs[nevs].offset = evpos - pos; + +				int i = mmap.lookup(key); +				if(i != -1) +				{ +					evs[nevs].instrument = i; +					evs[nevs].velocity = velocity / 127.0; + +					++nevs; +					if(nevs > 999) +					{ +						fprintf(stderr, "Midi event overflow\n"); +						break; +					} +				} +			} +		} + +		cur_event = smf_get_next_event(smf); +	} + +	if(!cur_event) +	{ +		if(loop) +		{ +			smf_rewind(smf); +			offset += cur_max_time; +		} +		else +		{ +			if(evs == nullptr) +			{ +				evs = (event_t *)malloc(sizeof(event_t) * 1000); +			} +			evs[nevs].type = TYPE_STOP; +			evs[nevs].offset = len - 1; +			++nevs; +		} +	} + +	*nevents = nevs; + +	return evs;  }  void MidiFile::post() @@ -199,73 +279,56 @@ void MidiFile::post()  }  extern "C" { -  void *create() -  { -    return new MidiFile(); -  } -   -  void destroy(void *h) -  { -    MidiFile *midifile = (MidiFile*)h; -    delete midifile; -  } - -  bool init(void *h, int i, char *inames[]) -  { -    MidiFile *midifile = (MidiFile*)h; -    return midifile->init(i, inames); -  } - -  void setparm(void *h, const char *parm, const char *value) -  { -    MidiFile *midifile = (MidiFile*)h; -    midifile->setParm(parm, value); -  } - -  bool start(void *h) -  { -    MidiFile *midifile = (MidiFile*)h; -    return midifile->start(); -  } - -  void stop(void *h) -  { -    MidiFile *midifile = (MidiFile*)h; -    midifile->stop(); -  } - -  void pre(void *h) -  { -    MidiFile *midifile = (MidiFile*)h; -    midifile->pre(); -  } - -  event_t *run(void *h, size_t pos, size_t len, size_t *nev) -  { -    MidiFile *midifile = (MidiFile*)h; -    return midifile->run(pos, len, nev); -  } - -  void post(void *h) -  { -    MidiFile *midifile = (MidiFile*)h; -    midifile->post(); -  } +	void *create() +	{ +		return new MidiFile(); +	} + +	void destroy(void *h) +	{ +		MidiFile *midifile = (MidiFile*)h; +		delete midifile; +	} + +	bool init(void *h, int i, char *inames[]) +	{ +		MidiFile *midifile = (MidiFile*)h; +		return midifile->init(i, inames); +	} + +	void setparm(void *h, const char *parm, const char *value) +	{ +		MidiFile *midifile = (MidiFile*)h; +		midifile->setParm(parm, value); +	} + +	bool start(void *h) +	{ +		MidiFile *midifile = (MidiFile*)h; +		return midifile->start(); +	} + +	void stop(void *h) +	{ +		MidiFile *midifile = (MidiFile*)h; +		midifile->stop(); +	} + +	void pre(void *h) +	{ +		MidiFile *midifile = (MidiFile*)h; +		midifile->pre(); +	} + +	event_t *run(void *h, size_t pos, size_t len, size_t *nev) +	{ +		MidiFile *midifile = (MidiFile*)h; +		return midifile->run(pos, len, nev); +	} + +	void post(void *h) +	{ +		MidiFile *midifile = (MidiFile*)h; +		midifile->post(); +	}  } - -#ifdef TEST_AUDIOINPUTENGINEMIDIFILE -//Additional dependency files -//deps: -//Required cflags (autoconf vars may be used) -//cflags: -//Required link options (autoconf vars may be used) -//libs: -#include "test.h" - -TEST_BEGIN; - -// TODO: Put some testcode here (see test.h for usable macros). - -TEST_END; - -#endif/*TEST_AUDIOINPUTENGINEMIDIFILE*/ | 
