123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- /*
- This file is part of QTau
- Copyright (C) 2013-2018 Tobias "Tomoko" Platen <tplaten@posteo.de>
- Copyright (C) 2013 digited <https://github.com/digited>
- Copyright (C) 2010-2013 HAL@ShurabaP <https://github.com/haruneko>
- QTau 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 3 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, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: GPL-3.0+
- */
- #include "midifile.h"
- #include <QJsonArray>
- #include <smf.h>
- #include "math.h"
- #include <QJsonObject>
- #include "ustjkeys.h"
- MidiFile::MidiFile()
- {
- }
- int MidiFile::saveMidi(const QJsonArray& ust,QString fileName)
- {
- //FIXME: ustJson(ust);
- smf_t *smf;
- smf_track_t *track;
- smf_event_t *event;
- smf = smf_new();
- track = smf_track_new();
- smf_add_track(smf, track);
- int bpm = 60;
- //int bpm = getTempo();
- track = smf_track_new();
- smf_add_track(smf, track);
- char temposig[6];
- int tempo=60*1000*1000/bpm;
- temposig[0] = 0xFF;
- temposig[1] = 0x51;
- temposig[2] = 0x03;
- temposig[3] = (tempo >> 16) & 0xFF;
- temposig[4] = (tempo >> 8) & 0xFF;
- temposig[5] = (tempo) & 0xFF;
- event = smf_event_new_from_pointer(temposig, 6);
- smf_track_add_event_pulses(track,event,0);
- char timesig[7];
- timesig[0] = 0xFF;
- timesig[1] = 0x58;
- timesig[2] = 0x04;
- //QJsonArray a = getTimeSignature();
- //int nn=a[0].toInt();
- //int dd=a[1].toInt();
- int nn = 4;
- int dd = 4;
- dd = log(dd)/log(2);
- timesig[3] = nn;
- timesig[4] = dd;
- timesig[5] = 0;
- timesig[6] = 8;
- event = smf_event_new_from_pointer(timesig, 7);
- smf_track_add_event_pulses(track,event,0);
- for (int i = 0; i < ust.count(); ++i)
- {
- auto o = ust[i];
- double ts = 0.25;
- unsigned char midi[3];
- midi[0]=0x90;
- midi[1]=o.toObject()[NOTE_KEY_NUMBER].toInt();
- midi[2]=100;//FIXME do not hardcode
- int noteOffset = o.toObject()[NOTE_PULSE_OFFSET].toInt();
- int noteLength = o.toObject()[NOTE_PULSE_LENGTH].toInt();
- if(noteLength>0)
- {
- event = smf_event_new_from_pointer(midi, 3);
- smf_track_add_event_pulses(track,event,ts*noteOffset);
- //http://www.ccarh.org/courses/253/handout/smf/
- QString lyric = o.toObject()[NOTE_LYRIC].toString();
- event = smf_event_new_textual(0x05,lyric.toUtf8());
- smf_track_add_event_pulses(track,event,ts*noteOffset);
- midi[0]=0x80;
- event = smf_event_new_from_pointer(midi, 3);
- smf_track_add_event_pulses(track,event,ts*(noteOffset+noteLength));
- }
- }
- return smf_save(smf, fileName.toUtf8());
- }
- void MidiFile::loadMidi(QString fileName,QJsonArray& ustRef)
- {
- smf_t *smf;
- smf_event_t *event;
- smf = smf_load(fileName.toUtf8());
- if(smf==NULL) return;
- smf_tempo_t* tempo = smf_get_tempo_by_pulses(smf,0);
- QJsonArray ts;
- ts.append(tempo->numerator);
- ts.append(tempo->denominator);
- //setTimeSignature(ts);
- float bpm=tempo->microseconds_per_quarter_note/(1000.0*1000.0);
- bpm=60.0/bpm;
- //setTempo(round(bpm));
- smf_track_t *track = smf_get_track_by_number(smf, smf->number_of_tracks);
- int activeNote = -1;
- int notePos = 0;
- QString text;
- for(int i=1;i<track->number_of_events+1;i++)
- {
- event = smf_track_get_event_by_number(track, i);
- if(smf_event_is_textual(event)){
- char* txt = smf_event_extract_text(event);
- text = txt;
- free(txt);
- }
- else
- {
- if(event->midi_buffer_length==3)
- {
- unsigned char status=event->midi_buffer[0];
- unsigned char statusb = 0xF0 & status;
- unsigned char notenum=event->midi_buffer[1];
- unsigned char velocity=event->midi_buffer[2];
- float factor=1;
- if(statusb == 0x80 || (statusb == 0x90 && velocity==0) )
- {
- //qDebug()<< "note off " <<notenum << " " <<velocity;
- int length = (event->time_pulses-notePos);
- QJsonObject note;
- //qDebug() << notePos << "::" << length;
- note[NOTE_PULSE_OFFSET]= notePos*factor;
- note[NOTE_PULSE_LENGTH]= length*factor;
- note[NOTE_KEY_NUMBER] = activeNote;
- note[NOTE_VELOCITY]=velocity;
- if(text.length()==0) text="[[a]]";
- note[NOTE_LYRIC] = text;
- ustRef.append(note);
- activeNote = -1;
- }
- else
- if(statusb == 0x90)
- {
- if(activeNote!=-1) {
- smf_delete(smf);
- return;
- }
- //qDebug() << "note on " << notenum;
- activeNote = notenum;
- notePos = event->time_pulses;
- }
- }
- }
- }
- smf_delete(smf);
- }
|