comparison data/fileio/MIDIFileWriter.cpp @ 852:d6bd5751b8f6 tonioni_multi_transform

Add NoteExportable base class, use it in MIDI export (and also elsewhere in playback)
author Chris Cannam
date Mon, 02 Dec 2013 17:11:20 +0000
parents 2e50d95cf621
children 59e7fe1b1003
comparison
equal deleted inserted replaced
850:dba8a02b0413 852:d6bd5751b8f6
21 */ 21 */
22 22
23 #include "MIDIFileWriter.h" 23 #include "MIDIFileWriter.h"
24 24
25 #include "data/midi/MIDIEvent.h" 25 #include "data/midi/MIDIEvent.h"
26 26 #include "model/NoteData.h"
27 #include "model/NoteModel.h"
28 27
29 #include "base/Pitch.h" 28 #include "base/Pitch.h"
30 29
31 #include <algorithm> 30 #include <algorithm>
32 #include <fstream> 31 #include <fstream>
35 using std::string; 34 using std::string;
36 using std::ios; 35 using std::ios;
37 36
38 using namespace MIDIConstants; 37 using namespace MIDIConstants;
39 38
40 MIDIFileWriter::MIDIFileWriter(QString path, NoteModel *model, float tempo) : 39 MIDIFileWriter::MIDIFileWriter(QString path, const NoteExportable *exportable,
40 int sampleRate, float tempo) :
41 m_path(path), 41 m_path(path),
42 m_model(model), 42 m_exportable(exportable),
43 m_modelUsesHz(false), 43 m_sampleRate(sampleRate),
44 m_tempo(tempo) 44 m_tempo(tempo)
45 { 45 {
46 if (model->getScaleUnits().toLower() == "hz") m_modelUsesHz = true;
47
48 if (!convert()) { 46 if (!convert()) {
49 m_error = "Conversion from model to internal MIDI format failed"; 47 m_error = "Conversion from model to internal MIDI format failed";
50 } 48 }
51 } 49 }
52 50
340 tempoString); 338 tempoString);
341 m_midiComposition[track].push_back(event); 339 m_midiComposition[track].push_back(event);
342 340
343 // Omit time signature 341 // Omit time signature
344 342
345 const NoteModel::PointList &notes = 343 NoteList notes = m_exportable->getNotes();
346 static_cast<SparseModel<Note> *>(m_model)->getPoints(); 344
347 345 for (NoteList::const_iterator i = notes.begin(); i != notes.end(); ++i) {
348 for (NoteModel::PointList::const_iterator i = notes.begin(); 346
349 i != notes.end(); ++i) { 347 size_t frame = i->start;
350
351 long frame = i->frame;
352 float value = i->value;
353 size_t duration = i->duration; 348 size_t duration = i->duration;
354 349 int pitch = i->midiPitch;
355 int pitch; 350 int velocity = i->velocity;
356
357 if (m_modelUsesHz) {
358 pitch = Pitch::getPitchForFrequency(value);
359 } else {
360 pitch = lrintf(value);
361 }
362 351
363 if (pitch < 0) pitch = 0; 352 if (pitch < 0) pitch = 0;
364 if (pitch > 127) pitch = 127; 353 if (pitch > 127) pitch = 127;
365 354
366 // Convert frame to MIDI time 355 // Convert frame to MIDI time
367 356
368 double seconds = double(frame) / double(m_model->getSampleRate()); 357 double seconds = double(frame) / double(m_sampleRate);
369 double quarters = (seconds * m_tempo) / 60.0; 358 double quarters = (seconds * m_tempo) / 60.0;
370 unsigned long midiTime = lrint(quarters * m_timingDivision); 359 unsigned long midiTime = int(quarters * m_timingDivision + 0.5);
371
372 int velocity = 100;
373 if (i->level > 0.f && i->level <= 1.f) {
374 velocity = lrintf(i->level * 127.f);
375 }
376 360
377 // Get the sounding time for the matching NOTE_OFF 361 // Get the sounding time for the matching NOTE_OFF
378 seconds = double(frame + duration) / double(m_model->getSampleRate()); 362 seconds = double(frame + duration) / double(m_sampleRate);
379 quarters = (seconds * m_tempo) / 60.0; 363 quarters = (seconds * m_tempo) / 60.0;
380 unsigned long endTime = lrint(quarters * m_timingDivision); 364 unsigned long endTime = int(quarters * m_timingDivision + 0.5);
381 365
382 // At this point all the notes we insert have absolute times 366 // At this point all the notes we insert have absolute times
383 // in the delta time fields. We resolve these into delta 367 // in the delta time fields. We resolve these into delta
384 // times further down (can't do it until all the note offs are 368 // times further down (can't do it until all the note offs are
385 // in place). 369 // in place).