midifile.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. This file is part of QTau
  3. Copyright (C) 2013-2018 Tobias "Tomoko" Platen <tplaten@posteo.de>
  4. Copyright (C) 2013 digited <https://github.com/digited>
  5. Copyright (C) 2010-2013 HAL@ShurabaP <https://github.com/haruneko>
  6. QTau is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. SPDX-License-Identifier: GPL-3.0+
  17. */
  18. #include "midifile.h"
  19. #include <QJsonArray>
  20. #include <smf.h>
  21. #include "math.h"
  22. #include <QJsonObject>
  23. #include "ustjkeys.h"
  24. MidiFile::MidiFile()
  25. {
  26. }
  27. int MidiFile::saveMidi(const QJsonArray& ust,QString fileName)
  28. {
  29. //FIXME: ustJson(ust);
  30. smf_t *smf;
  31. smf_track_t *track;
  32. smf_event_t *event;
  33. smf = smf_new();
  34. track = smf_track_new();
  35. smf_add_track(smf, track);
  36. int bpm = 60;
  37. //int bpm = getTempo();
  38. track = smf_track_new();
  39. smf_add_track(smf, track);
  40. char temposig[6];
  41. int tempo=60*1000*1000/bpm;
  42. temposig[0] = 0xFF;
  43. temposig[1] = 0x51;
  44. temposig[2] = 0x03;
  45. temposig[3] = (tempo >> 16) & 0xFF;
  46. temposig[4] = (tempo >> 8) & 0xFF;
  47. temposig[5] = (tempo) & 0xFF;
  48. event = smf_event_new_from_pointer(temposig, 6);
  49. smf_track_add_event_pulses(track,event,0);
  50. char timesig[7];
  51. timesig[0] = 0xFF;
  52. timesig[1] = 0x58;
  53. timesig[2] = 0x04;
  54. //QJsonArray a = getTimeSignature();
  55. //int nn=a[0].toInt();
  56. //int dd=a[1].toInt();
  57. int nn = 4;
  58. int dd = 4;
  59. dd = log(dd)/log(2);
  60. timesig[3] = nn;
  61. timesig[4] = dd;
  62. timesig[5] = 0;
  63. timesig[6] = 8;
  64. event = smf_event_new_from_pointer(timesig, 7);
  65. smf_track_add_event_pulses(track,event,0);
  66. for (int i = 0; i < ust.count(); ++i)
  67. {
  68. auto o = ust[i];
  69. double ts = 0.25;
  70. unsigned char midi[3];
  71. midi[0]=0x90;
  72. midi[1]=o.toObject()[NOTE_KEY_NUMBER].toInt();
  73. midi[2]=100;//FIXME do not hardcode
  74. int noteOffset = o.toObject()[NOTE_PULSE_OFFSET].toInt();
  75. int noteLength = o.toObject()[NOTE_PULSE_LENGTH].toInt();
  76. if(noteLength>0)
  77. {
  78. event = smf_event_new_from_pointer(midi, 3);
  79. smf_track_add_event_pulses(track,event,ts*noteOffset);
  80. //http://www.ccarh.org/courses/253/handout/smf/
  81. QString lyric = o.toObject()[NOTE_LYRIC].toString();
  82. event = smf_event_new_textual(0x05,lyric.toUtf8());
  83. smf_track_add_event_pulses(track,event,ts*noteOffset);
  84. midi[0]=0x80;
  85. event = smf_event_new_from_pointer(midi, 3);
  86. smf_track_add_event_pulses(track,event,ts*(noteOffset+noteLength));
  87. }
  88. }
  89. return smf_save(smf, fileName.toUtf8());
  90. }
  91. void MidiFile::loadMidi(QString fileName,QJsonArray& ustRef)
  92. {
  93. smf_t *smf;
  94. smf_event_t *event;
  95. smf = smf_load(fileName.toUtf8());
  96. if(smf==NULL) return;
  97. smf_tempo_t* tempo = smf_get_tempo_by_pulses(smf,0);
  98. QJsonArray ts;
  99. ts.append(tempo->numerator);
  100. ts.append(tempo->denominator);
  101. //setTimeSignature(ts);
  102. float bpm=tempo->microseconds_per_quarter_note/(1000.0*1000.0);
  103. bpm=60.0/bpm;
  104. //setTempo(round(bpm));
  105. smf_track_t *track = smf_get_track_by_number(smf, smf->number_of_tracks);
  106. int activeNote = -1;
  107. int notePos = 0;
  108. QString text;
  109. for(int i=1;i<track->number_of_events+1;i++)
  110. {
  111. event = smf_track_get_event_by_number(track, i);
  112. if(smf_event_is_textual(event)){
  113. char* txt = smf_event_extract_text(event);
  114. text = txt;
  115. free(txt);
  116. }
  117. else
  118. {
  119. if(event->midi_buffer_length==3)
  120. {
  121. unsigned char status=event->midi_buffer[0];
  122. unsigned char statusb = 0xF0 & status;
  123. unsigned char notenum=event->midi_buffer[1];
  124. unsigned char velocity=event->midi_buffer[2];
  125. float factor=1;
  126. if(statusb == 0x80 || (statusb == 0x90 && velocity==0) )
  127. {
  128. //qDebug()<< "note off " <<notenum << " " <<velocity;
  129. int length = (event->time_pulses-notePos);
  130. QJsonObject note;
  131. //qDebug() << notePos << "::" << length;
  132. note[NOTE_PULSE_OFFSET]= notePos*factor;
  133. note[NOTE_PULSE_LENGTH]= length*factor;
  134. note[NOTE_KEY_NUMBER] = activeNote;
  135. note[NOTE_VELOCITY]=velocity;
  136. if(text.length()==0) text="[[a]]";
  137. note[NOTE_LYRIC] = text;
  138. ustRef.append(note);
  139. activeNote = -1;
  140. }
  141. else
  142. if(statusb == 0x90)
  143. {
  144. if(activeNote!=-1) {
  145. smf_delete(smf);
  146. return;
  147. }
  148. //qDebug() << "note on " << notenum;
  149. activeNote = notenum;
  150. notePos = event->time_pulses;
  151. }
  152. }
  153. }
  154. }
  155. smf_delete(smf);
  156. }