| 5 | #include "MidiFileWriter.h" |
| 6 | |
| 7 | bool MidiFileWriter::writeMidiFile(const std::vector<Notes::Event>& inNoteEvents, |
| 8 | const File& fileToUse, |
| 9 | const TimeQuantizeOptions::TimeQuantizeInfo& inInfo, |
| 10 | double inExportBpm, |
| 11 | PitchBendModes inPitchBendMode) const |
| 12 | { |
| 13 | // Compute offset to start at beginning of the previous bar |
| 14 | const double start_offset = - inInfo.getStartLastBarSec(); |
| 15 | jassert(start_offset >= 0.0); |
| 16 | |
| 17 | MidiMessageSequence message_sequence; |
| 18 | |
| 19 | // Set tempo |
| 20 | auto tempo_meta_event = |
| 21 | MidiMessage::tempoMetaEvent(static_cast<int>(std::round(_BPMToMicrosecondsPerQuarterNote(inExportBpm)))); |
| 22 | tempo_meta_event.setTimeStamp(0.0); |
| 23 | message_sequence.addEvent(tempo_meta_event); |
| 24 | |
| 25 | // Set time signature |
| 26 | auto time_signature_meta_event = |
| 27 | MidiMessage::timeSignatureMetaEvent(inInfo.timeSignatureNum, inInfo.timeSignatureDenom); |
| 28 | time_signature_meta_event.setTimeStamp(0.0); |
| 29 | message_sequence.addEvent(time_signature_meta_event); |
| 30 | |
| 31 | float prev_pitch_bend_semitone = 0.0f; |
| 32 | |
| 33 | // Add note events |
| 34 | for (auto& note: inNoteEvents) { |
| 35 | auto note_on = MidiMessage::noteOn(1, note.pitch, static_cast<float>(note.amplitude)); |
| 36 | note_on.setTimeStamp((note.startTime + start_offset) * inExportBpm / 60.0 * mTicksPerQuarterNote); |
| 37 | |
| 38 | auto note_off = MidiMessage::noteOff(1, note.pitch); |
| 39 | note_off.setTimeStamp((note.endTime + start_offset) * inExportBpm / 60.0 * mTicksPerQuarterNote); |
| 40 | |
| 41 | message_sequence.addEvent(note_on); |
| 42 | |
| 43 | // Add pitch bend event |
| 44 | if (inPitchBendMode == SinglePitchBend) { |
| 45 | for (size_t i = 0; i < note.bends.size(); i++) { |
| 46 | prev_pitch_bend_semitone = static_cast<float>(note.bends[i]) / 3.0f; |
| 47 | auto pitch_wheel_pos = MidiMessage::pitchbendToPitchwheelPos(prev_pitch_bend_semitone, 4.0f); |
| 48 | auto pitch_wheel_event = MidiMessage::pitchWheel(1, pitch_wheel_pos); |
| 49 | pitch_wheel_event.setTimeStamp((note.startTime + start_offset + i * FFT_HOP / BASIC_PITCH_SAMPLE_RATE) |
| 50 | * inExportBpm / 60.0 * mTicksPerQuarterNote); |
| 51 | message_sequence.addEvent(pitch_wheel_event); |
| 52 | } |
| 53 | |
| 54 | if (note.bends.empty() && prev_pitch_bend_semitone != 0) { |
| 55 | prev_pitch_bend_semitone = 0.0f; |
| 56 | auto pitch_wheel_pos = MidiMessage::pitchbendToPitchwheelPos(0.0f, 4.0f); |
| 57 | auto pitch_wheel_event = MidiMessage::pitchWheel(1, pitch_wheel_pos); |
| 58 | pitch_wheel_event.setTimeStamp((note.startTime + start_offset) * inExportBpm / 60.0 |
| 59 | * mTicksPerQuarterNote); |
| 60 | message_sequence.addEvent(pitch_wheel_event); |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | message_sequence.addEvent(note_off); |
no test coverage detected