1379 lines
54 KiB
C++
1379 lines
54 KiB
C++
//=============================================================================
|
|
// MuseScore
|
|
// Linux Music Score Editor
|
|
// $Id: importmidi.cpp 5568 2012-04-22 10:08:43Z wschweer $
|
|
//
|
|
// Copyright (C) 2002-2011 Werner Schweer and others
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License version 2.
|
|
//
|
|
// 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, write to the Free Software
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
//=============================================================================
|
|
|
|
#include "libmscore/midifile.h"
|
|
#include "scoreview.h"
|
|
#include "file.h"
|
|
#include "libmscore/score.h"
|
|
#include "libmscore/key.h"
|
|
#include "libmscore/clef.h"
|
|
#include "libmscore/sig.h"
|
|
#include "libmscore/tempo.h"
|
|
#include "libmscore/note.h"
|
|
#include "libmscore/chord.h"
|
|
#include "libmscore/rest.h"
|
|
#include "libmscore/segment.h"
|
|
#include "libmscore/utils.h"
|
|
#include "libmscore/text.h"
|
|
#include "libmscore/slur.h"
|
|
#include "libmscore/staff.h"
|
|
#include "libmscore/measure.h"
|
|
#include "libmscore/style.h"
|
|
#include "libmscore/part.h"
|
|
#include "libmscore/timesig.h"
|
|
#include "libmscore/barline.h"
|
|
#include "libmscore/pedal.h"
|
|
#include "libmscore/ottava.h"
|
|
#include "libmscore/lyrics.h"
|
|
#include "libmscore/bracket.h"
|
|
#include "libmscore/keyfinder.h"
|
|
#include "libmscore/drumset.h"
|
|
#include "preferences.h"
|
|
#include "libmscore/box.h"
|
|
#include "libmscore/keysig.h"
|
|
#include "libmscore/pitchspelling.h"
|
|
|
|
static unsigned const char gmOnMsg[] = { 0x7e, 0x7f, 0x09, 0x01 };
|
|
static unsigned const char gsOnMsg[] = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41 };
|
|
static unsigned const char xgOnMsg[] = { 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00 };
|
|
static unsigned const int gmOnMsgLen = sizeof(gmOnMsg);
|
|
static unsigned const int gsOnMsgLen = sizeof(gsOnMsg);
|
|
static unsigned const int xgOnMsgLen = sizeof(xgOnMsg);
|
|
|
|
//---------------------------------------------------------
|
|
// MidiInstrument
|
|
//---------------------------------------------------------
|
|
|
|
struct MidiInstrument {
|
|
int type;
|
|
int hbank, lbank, patch;
|
|
int split;
|
|
const char* name;
|
|
};
|
|
|
|
static MidiInstrument minstr[] = {
|
|
// Piano
|
|
{ 7, 0, 0, 0, 60, "Grand Piano" },
|
|
{ 4, 0, 1, 0, 60, "GrndPnoK" },
|
|
{ 4, 0, 18, 0, 60, "MelloGrP" },
|
|
{ 4, 0, 40, 0, 60, "PianoStr" },
|
|
{ 4, 0, 41, 0, 60, "Dream" },
|
|
{ 7, 0, 0, 1, 60, "Bright Piano" },
|
|
{ 4, 0, 1, 1, 60, "BritPnoK" },
|
|
{ 7, 0, 0, 2, 60, "E.Grand" },
|
|
{ 4, 0, 1, 2, 60, "ElGrPnoK" },
|
|
{ 4, 0, 32, 2, 60, "Det.CP80" },
|
|
{ 4, 0, 40, 2, 60, "ElGrPno1" },
|
|
{ 4, 0, 41, 2, 60, "ElGrPno2" },
|
|
{ 7, 0, 0, 3, 60, "Honky-tonk" },
|
|
{ 4, 0, 1, 3, 60, "HonkyTonkK" },
|
|
{ 7, 0, 0, 4, 60, "E.Piano" },
|
|
{ 4, 0, 1, 4, 60, "El.Pno1K" },
|
|
{ 4, 0, 18, 4, 60, "MelloEP1" },
|
|
{ 4, 0, 32, 4, 60, "Chor.EP1" },
|
|
{ 4, 0, 40, 4, 60, "HardEl.P" },
|
|
{ 4, 0, 45, 4, 60, "VXElP1" },
|
|
{ 4, 0, 64, 4, 60, "60sEl.P" },
|
|
{ 7, 0, 0, 5, 60, "E.Piano 2" },
|
|
{ 4, 0, 1, 5, 60, "El.Pno2K" },
|
|
{ 4, 0, 32, 5, 60, "Chor.EP2" },
|
|
{ 4, 0, 33, 5, 60, "DX.Hard" },
|
|
{ 4, 0, 34, 5, 60, "DXLegend" },
|
|
{ 4, 0, 40, 5, 60, "DXPhase" },
|
|
{ 4, 0, 41, 5, 60, "DX+Analg" },
|
|
{ 4, 0, 42, 5, 60, "DXKotoEP" },
|
|
{ 4, 0, 45, 5, 60, "VXEl.P2" },
|
|
{ 7, 0, 0, 6, 60, "Harpsichord" },
|
|
{ 4, 0, 1, 6, 60, "Harpsi.K" },
|
|
{ 4, 0, 25, 6, 60, "Harpsi.2" },
|
|
{ 4, 0, 35, 6, 60, "Harpsi.3" },
|
|
{ 7, 0, 0, 7, 60, "Clav." },
|
|
{ 4, 0, 1, 7, 60, "Clavi.K" },
|
|
{ 4, 0, 27, 7, 60, "ClaviWah" },
|
|
{ 4, 0, 64, 7, 60, "PulseClv" },
|
|
{ 4, 0, 65, 7, 60, "PierceCl" },
|
|
|
|
// Chromatic Perc
|
|
{ 7, 0, 0, 8, 0, "Celesta" },
|
|
{ 7, 0, 0, 9, 0, "Glockenspiel" },
|
|
{ 7, 0, 0, 10, 0, "Music Box" },
|
|
{ 4, 0, 64, 10, 0, "Orgel" },
|
|
{ 7, 0, 0, 11, 0, "Vibraphone" },
|
|
{ 4, 0, 1, 11, 0, "VibesK" },
|
|
{ 4, 0, 45, 11, 0, "HardVibe" },
|
|
{ 7, 0, 0, 12, 0, "Marimba" },
|
|
{ 4, 0, 1, 12, 0, "MarimbaK" },
|
|
{ 4, 0, 64, 12, 0, "SineMrmb" },
|
|
{ 4, 0, 96, 12, 0, "Balafon" },
|
|
{ 4, 0, 97, 12, 0, "Balafon2" },
|
|
{ 4, 0, 98, 12, 0, "LogDrum" },
|
|
{ 7, 0, 0, 13, 0, "Xylophone" },
|
|
{ 7, 0, 0, 14, 0, "Tubular Bells" },
|
|
{ 4, 0, 96, 14, 0, "ChrchBel" },
|
|
{ 4, 0, 97, 14, 0, "Carillon" },
|
|
{ 7, 0, 0, 15, 0, "Dulcimer" },
|
|
{ 4, 0, 35, 15, 0, "Dulcimr2" },
|
|
{ 4, 0, 96, 15, 0, "Cimbalom" },
|
|
{ 4, 0, 97, 15, 0, "Santur" },
|
|
// Organ
|
|
{ 7, 0, 0, 16, 0, "Drawbar Organ" },
|
|
{ 4, 0, 32, 16, 0, "DelDrwOr" },
|
|
{ 4, 0, 33, 16, 0, "60sDrOr1" },
|
|
{ 4, 0, 34, 16, 0, "60sDrOr2" },
|
|
{ 4, 0, 35, 16, 0, "70sDrOr1" },
|
|
{ 4, 0, 36, 16, 0, "DrawOrg2" },
|
|
{ 4, 0, 37, 16, 0, "60sDrOr3" },
|
|
{ 4, 0, 38, 16, 0, "EvenBar" },
|
|
{ 4, 0, 40, 16, 0, "16+2\"2/3" },
|
|
{ 4, 0, 64, 16, 0, "OrganBa" },
|
|
{ 4, 0, 65, 16, 0, "70sDrOr2" },
|
|
{ 4, 0, 66, 16, 0, "CheezOrg" },
|
|
{ 4, 0, 67, 16, 0, "DrawOrg3" },
|
|
{ 7, 0, 0, 17, 0, "Perc. Organ" },
|
|
{ 4, 0, 24, 17, 0, "70sPcOr1" },
|
|
{ 4, 0, 32, 17, 0, "DetPrcOr" },
|
|
{ 4, 0, 33, 17, 0, "LiteOrg" },
|
|
{ 4, 0, 37, 17, 0, "PercOrg2" },
|
|
{ 7, 0, 0, 18, 0, "Rock Organ" },
|
|
{ 4, 0, 64, 18, 0, "RotaryOr" },
|
|
{ 4, 0, 65, 18, 0, "SloRotar" },
|
|
{ 4, 0, 66, 18, 0, "FstRotar" },
|
|
{ 7, 0, 0, 19, 0, "Church Organ" },
|
|
{ 4, 0, 32, 19, 0, "ChurOrg3" },
|
|
{ 4, 0, 35, 19, 0, "ChurOrg2" },
|
|
{ 4, 0, 40, 19, 0, "NotreDam" },
|
|
{ 4, 0, 64, 19, 0, "OrgFlute" },
|
|
{ 4, 0, 65, 19, 0, "TrmOrgFl" },
|
|
{ 7, 0, 0, 20, 0, "Reed Organ" },
|
|
{ 4, 0, 40, 20, 0, "PuffOrg" },
|
|
{ 7, 0, 0, 21, 0, "Akkordion" },
|
|
{ 4, 0, 32, 21, 0, "Accordlt" },
|
|
{ 7, 0, 0, 22, 0, "Harmonica" },
|
|
{ 4, 0, 32, 22, 0, "Harmo2" },
|
|
{ 7, 0, 0, 23, 0, "Bandoneon" },
|
|
{ 4, 0, 64, 23, 0, "TngoAcd2" },
|
|
// Guitar
|
|
{ 7, 0, 0, 24, 0, "Nylon Gtr." },
|
|
{ 4, 0, 16, 24, 0, "NylonGt2" },
|
|
{ 4, 0, 25, 24, 0, "NylonGt3" },
|
|
{ 4, 0, 43, 24, 0, "VelGtHrm" },
|
|
{ 4, 0, 96, 24, 0, "Ukelele" },
|
|
{ 7, 0, 0, 25, 0, "Steel Gtr." },
|
|
{ 4, 0, 16, 25, 0, "SteelGt2" },
|
|
{ 4, 0, 35, 25, 0, "12StrGtr" },
|
|
{ 4, 0, 40, 25, 0, "Nylon-Stl" },
|
|
{ 4, 0, 41, 25, 0, "Stl-Body" },
|
|
{ 4, 0, 96, 25, 0, "Mandolin" },
|
|
{ 7, 0, 0, 26, 0, "Jazz Guitar" },
|
|
{ 4, 0, 18, 26, 0, "MelloGtr" },
|
|
{ 4, 0, 32, 26, 0, "JazzAmp" },
|
|
{ 4, 0, 96, 26, 0, "PdlSteel" },
|
|
{ 7, 0, 0, 27, 0, "Clean Guitar" },
|
|
{ 4, 0, 32, 27, 0, "ChorusGt" },
|
|
{ 4, 0, 64, 27, 0, "CleanGt2" },
|
|
{ 7, 0, 0, 28, 0, "Muted Guitar" },
|
|
{ 4, 0, 40, 28, 0, "FunkGtr1" },
|
|
{ 4, 0, 41, 28, 0, "MuteStlG" },
|
|
{ 4, 0, 43, 28, 0, "FunkGtr2" },
|
|
{ 4, 0, 45, 28, 0, "JazzMan" },
|
|
{ 4, 0, 96, 28, 0, "Mu.DstGt" },
|
|
{ 7, 0, 0, 29, 0, "Overdrive Gtr" },
|
|
{ 4, 0, 43, 29, 0, "Gt.Pinch" },
|
|
{ 7, 0, 0, 30, 0, "DistortionGtr" },
|
|
{ 4, 0, 12, 30, 0, "DstRthmG" },
|
|
{ 4, 0, 24, 30, 0, "DistGtr2" },
|
|
{ 4, 0, 35, 30, 0, "DistGtr3" },
|
|
{ 4, 0, 36, 30, 0, "PowerGt2" },
|
|
{ 4, 0, 37, 30, 0, "PowerGt1" },
|
|
{ 4, 0, 38, 30, 0, "Dst.5ths" },
|
|
{ 4, 0, 40, 30, 0, "FeedbkGt" },
|
|
{ 4, 0, 41, 30, 0, "FeedbGt2" },
|
|
{ 4, 0, 43, 30, 0, "RkRythm2" },
|
|
{ 4, 0, 45, 30, 0, "RockRthm" },
|
|
{ 7, 0, 0, 31, 0, "Gtr.Harmonics" },
|
|
{ 4, 0, 65, 31, 0, "GtFeedbk" },
|
|
{ 4, 0, 66, 31, 0, "GtrHrmo2" },
|
|
{ 4, 0, 64, 31, 0, "AcoHarmo" },
|
|
// Bass
|
|
{ 7, 0, 0, 32, 0, "Acoustic Bass" },
|
|
{ 4, 0, 40, 32, 0, "JazzRthm" },
|
|
{ 4, 0, 45, 32, 0, "VXUprght" },
|
|
{ 7, 0, 0, 33, 0, "Fingered Bass" },
|
|
{ 4, 0, 18, 33, 0, "FingrDrk" },
|
|
{ 4, 0, 27, 33, 0, "FlangeBa" },
|
|
{ 4, 0, 40, 33, 0, "Ba-DstEG" },
|
|
{ 4, 0, 43, 33, 0, "FngrSlap" },
|
|
{ 4, 0, 45, 33, 0, "FngBass2" },
|
|
{ 4, 0, 64, 33, 0, "JazzBass" },
|
|
{ 4, 0, 65, 33, 0, "ModAlem" },
|
|
{ 7, 0, 0, 34, 0, "Picked Bass" },
|
|
{ 4, 0, 28, 34, 0, "MutePkBa" },
|
|
{ 7, 0, 0, 35, 0, "Fretless Bass" },
|
|
{ 4, 0, 32, 35, 0, "Fretles2" },
|
|
{ 4, 0, 33, 35, 0, "Fretles3" },
|
|
{ 4, 0, 34, 35, 0, "Fretles4" },
|
|
{ 4, 0, 96, 35, 0, "SynFretl" },
|
|
{ 4, 0, 97, 35, 0, "Smooth" },
|
|
{ 7, 0, 0, 36, 0, "Slap Bass 1" },
|
|
{ 4, 0, 27, 36, 0, "ResoSlap" },
|
|
{ 4, 0, 32, 36, 0, "PunchThm" },
|
|
{ 7, 0, 0, 37, 0, "Slap Bass 2" },
|
|
{ 4, 0, 43, 37, 0, "VeloSlap" },
|
|
{ 7, 0, 0, 38, 0, "Synth Bass 1" },
|
|
{ 4, 0, 18, 38, 0, "SynBa1Dk" },
|
|
{ 4, 0, 20, 38, 0, "FastResB" },
|
|
{ 4, 0, 24, 38, 0, "AcidBass" },
|
|
{ 4, 0, 35, 38, 0, "ClvBass" },
|
|
{ 4, 0, 40, 38, 0, "TeknoBa" },
|
|
{ 4, 0, 64, 38, 0, "Oscar" },
|
|
{ 4, 0, 65, 38, 0, "SqrBass" },
|
|
{ 4, 0, 66, 38, 0, "RubberBa" },
|
|
{ 4, 0, 96, 38, 0, "Hammer" },
|
|
{ 7, 0, 0, 39, 0, "Synth Bass 2" },
|
|
{ 4, 0, 6, 39, 0, "MelloSB1" },
|
|
{ 4, 0, 12, 39, 0, "SeqBass" },
|
|
{ 4, 0, 18, 39, 0, "ClkSynBa" },
|
|
{ 4, 0, 19, 39, 0, "SynBa2Dk" },
|
|
{ 4, 0, 32, 39, 0, "SmthBa2" },
|
|
{ 4, 0, 40, 39, 0, "ModulrBa" },
|
|
{ 4, 0, 41, 39, 0, "DXBass" },
|
|
{ 4, 0, 64, 39, 0, "XWireBa" },
|
|
// Strings/Orch
|
|
{ 7, 0, 0, 40, 0, "Violin" },
|
|
{ 4, 0, 8, 40, 0, "SlowVln" },
|
|
{ 7, 0, 0, 41, 0, "Viola" },
|
|
{ 7, 0, 0, 42, 0, "Cello" },
|
|
{ 7, 0, 0, 43, 0, "Contrabass" },
|
|
{ 7, 0, 0, 44, 0, "Tremolo Str." },
|
|
{ 4, 0, 8, 44, 0, "SlowTrSt" },
|
|
{ 4, 0, 40, 44, 0, "SuspStr" },
|
|
{ 7, 0, 0, 45, 0, "PizzicatoStr." },
|
|
{ 7, 0, 0, 46, 0, "Harp" },
|
|
{ 4, 0, 40, 46, 0, "YangChin" },
|
|
{ 7, 0, 0, 47, 0, "Timpani" },
|
|
// Ensemble
|
|
{ 7, 0, 0, 48, 0, "Strings 1" },
|
|
{ 4, 0, 3, 48, 0, "S.Strngs" },
|
|
{ 4, 0, 8, 48, 0, "SlowStr" },
|
|
{ 4, 0, 24, 48, 0, "ArcoStr" },
|
|
{ 4, 0, 35, 48, 0, "60sStrng" },
|
|
{ 4, 0, 40, 48, 0, "Orchestr" },
|
|
{ 4, 0, 41, 48, 0, "Orchstr2" },
|
|
{ 4, 0, 42, 48, 0, "TremOrch" },
|
|
{ 4, 0, 45, 48, 0, "VeloStr" },
|
|
{ 7, 0, 0, 49, 0, "Strings 2" },
|
|
{ 4, 0, 3, 49, 0, "S.SlwStr" },
|
|
{ 4, 0, 8, 49, 0, "LegatoSt" },
|
|
{ 4, 0, 40, 49, 0, "WarmStr" },
|
|
{ 4, 0, 41, 49, 0, "Kingdom" },
|
|
{ 4, 0, 64, 49, 0, "70sStr" },
|
|
{ 4, 0, 65, 49, 0, "StrEns3" },
|
|
{ 7, 0, 0, 50, 0, "Syn.Strings 1" },
|
|
{ 4, 0, 27, 50, 0, "ResoStr" },
|
|
{ 4, 0, 64, 50, 0, "SynStr4" },
|
|
{ 4, 0, 65, 50, 0, "SSStr" },
|
|
{ 4, 0, 35, 50, 0, "SynStr3" },
|
|
{ 7, 0, 0, 51, 0, "Syn.Strings 2" },
|
|
{ 7, 0, 0, 52, 0, "Choir Aahs" },
|
|
{ 4, 0, 3, 52, 0, "S.Choir" },
|
|
{ 4, 0, 16, 52, 0, "Ch.Aahs2" },
|
|
{ 4, 0, 32, 52, 0, "MelChoir" },
|
|
{ 4, 0, 40, 52, 0, "ChoirStr" },
|
|
{ 4, 0, 64, 52, 0, "StrngAah" },
|
|
{ 4, 0, 65, 52, 0, "MaleAah" },
|
|
{ 7, 0, 0, 53, 0, "Voice Oohs" },
|
|
{ 4, 0, 64, 53, 0, "VoiceDoo" },
|
|
{ 4, 0, 96, 53, 0, "VoiceHmn" },
|
|
{ 7, 0, 0, 54, 0, "Synth Voice" },
|
|
{ 4, 0, 40, 54, 0, "SynVox2" },
|
|
{ 4, 0, 41, 54, 0, "Choral" },
|
|
{ 4, 0, 64, 54, 0, "AnaVoice" },
|
|
{ 7, 0, 0, 55, 0, "Orchestra Hit" },
|
|
{ 4, 0, 35, 55, 0, "OrchHit2" },
|
|
{ 4, 0, 64, 55, 0, "Impact" },
|
|
{ 4, 0, 66, 55, 0, "DoublHit" },
|
|
{ 4, 0, 67, 55, 0, "BrStab80" },
|
|
// Brass
|
|
{ 7, 0, 0, 56, 0, "Trumpet" },
|
|
{ 4, 0, 16, 56, 0, "Trumpet2" },
|
|
{ 4, 0, 17, 56, 0, "BriteTrp" },
|
|
{ 4, 0, 32, 56, 0, "WarmTrp" },
|
|
{ 4, 0, 96, 56, 0, "FluglHrn" },
|
|
{ 7, 0, 0, 57, 0, "Trombone" },
|
|
{ 4, 0, 18, 57, 0, "Trmbone2" },
|
|
{ 7, 0, 0, 58, 0, "Tuba" },
|
|
{ 4, 0, 16, 58, 0, "Tuba2" },
|
|
{ 7, 0, 0, 59, 0, "Muted Trumpet" },
|
|
{ 4, 2, 64, 59, 0, "MuteTrp2" },
|
|
{ 7, 0, 0, 60, 0, "French Horn" },
|
|
{ 4, 0, 6, 60, 0, "FrHrSolo" },
|
|
{ 4, 0, 32, 60, 0, "FrHorn2" },
|
|
{ 4, 0, 37, 60, 0, "HornOrch" },
|
|
{ 7, 0, 0, 61, 0, "Brass Section" },
|
|
{ 4, 0, 35, 61, 0, "Tp-TbSec" },
|
|
{ 4, 0, 40, 61, 0, "BrssSec2" },
|
|
{ 4, 0, 41, 61, 0, "HiBrass" },
|
|
{ 4, 0, 42, 61, 0, "MelloBrs" },
|
|
{ 4, 0, 14, 61, 0, "SfrzndBr" },
|
|
{ 4, 0, 39, 61, 0, "BrssFall" },
|
|
{ 7, 0, 0, 62, 0, "Synth Brass 1" },
|
|
{ 4, 0, 12, 62, 0, "QuackBr" },
|
|
{ 4, 0, 20, 62, 0, "RezSynBr" },
|
|
{ 4, 0, 24, 62, 0, "PolyBrss" },
|
|
{ 4, 0, 27, 62, 0, "SynBras3" },
|
|
{ 4, 0, 32, 62, 0, "JumpBrss" },
|
|
{ 4, 0, 45, 62, 0, "AnaVelBr" },
|
|
{ 4, 0, 64, 62, 0, "AnaBrss1" },
|
|
{ 7, 0, 0, 63, 0, "Synth Brass 2" },
|
|
{ 4, 0, 18, 63, 0, "SoftBrs" },
|
|
{ 4, 0, 40, 63, 0, "SynBras4" },
|
|
{ 4, 0, 41, 63, 0, "ChoBrss" },
|
|
{ 4, 0, 45, 63, 0, "VelBras2" },
|
|
{ 4, 0, 64, 63, 0, "AnaBras2" },
|
|
// Reed
|
|
{ 7, 0, 0, 64, 0, "Soprano Sax" },
|
|
{ 7, 0, 0, 65, 0, "Alto Sax" },
|
|
{ 4, 0, 40, 65, 0, "SaxSect" },
|
|
{ 4, 0, 43, 65, 0, "HyprAlto" },
|
|
{ 7, 0, 0, 66, 0, "Tenor Sax" },
|
|
{ 4, 0, 40, 66, 0, "BrthTnSx" },
|
|
{ 4, 0, 41, 66, 0, "SoftTenr" },
|
|
{ 4, 0, 64, 66, 0, "TnrSax2" },
|
|
{ 7, 0, 0, 67, 0, "Baritone Sax" },
|
|
{ 7, 0, 0, 68, 0, "Oboe" },
|
|
{ 7, 0, 0, 69, 0, "English Horn" },
|
|
{ 7, 0, 0, 70, 0, "Bassoon" },
|
|
{ 7, 0, 0, 71, 0, "Clarinet" },
|
|
{ 4, 0, 96, 71, 0, "BassClar" },
|
|
// Pipe
|
|
{ 7, 0, 0, 72, 0, "Piccolo" },
|
|
{ 7, 0, 0, 73, 0, "Flute" },
|
|
{ 7, 0, 0, 74, 0, "Recorder" },
|
|
{ 7, 0, 0, 75, 0, "Pan Flute" },
|
|
{ 4, 0, 64, 75, 0, "PanFlut2" },
|
|
{ 4, 0, 96, 75, 0, "Kawala" },
|
|
{ 7, 0, 0, 76, 0, "Blown Bottle" },
|
|
{ 7, 0, 0, 77, 0, "Shakuhachi" },
|
|
{ 7, 0, 0, 78, 0, "Whistle" },
|
|
{ 7, 0, 0, 79, 0, "Ocarina" },
|
|
// SynthLead
|
|
{ 7, 0, 0, 80, 0, "Square Wave" },
|
|
{ 4, 0, 6, 80, 0, "Square2" },
|
|
{ 4, 0, 8, 80, 0, "LMSquare" },
|
|
{ 4, 0, 18, 80, 0, "Hollow" },
|
|
{ 4, 0, 19, 80, 0, "Shmoog" },
|
|
{ 4, 0, 64, 80, 0, "Mellow" },
|
|
{ 4, 0, 65, 80, 0, "SoloSine" },
|
|
{ 4, 0, 66, 80, 0, "SineLead" },
|
|
{ 7, 0, 0, 81, 0, "Saw Wave" },
|
|
{ 4, 0, 6, 81, 0, "Saw2" },
|
|
{ 4, 0, 8, 81, 0, "ThickSaw" },
|
|
{ 4, 0, 18, 81, 0, "DynaSaw" },
|
|
{ 4, 0, 19, 81, 0, "DigiSaw" },
|
|
{ 4, 0, 20, 81, 0, "BigLead" },
|
|
{ 4, 0, 24, 81, 0, "HeavySyn" },
|
|
{ 4, 0, 25, 81, 0, "WaspySyn" },
|
|
{ 4, 0, 40, 81, 0, "PulseSaw" },
|
|
{ 4, 0, 41, 81, 0, "Dr.Lead" },
|
|
{ 4, 0, 45, 81, 0, "VeloLead" },
|
|
{ 4, 0, 96, 81, 0, "SeqAna" },
|
|
{ 7, 0, 0, 82, 0, "Calliope" },
|
|
{ 4, 0, 65, 82, 0, "PurePad" },
|
|
{ 4, 0, 64, 82, 0, "VentSyn" },
|
|
{ 7, 0, 0, 83, 0, "Chiffer Lead" },
|
|
{ 4, 0, 64, 83, 0, "Rubby" },
|
|
{ 7, 0, 0, 84, 0, "Charang" },
|
|
{ 4, 0, 64, 84, 0, "DistLead" },
|
|
{ 4, 0, 65, 84, 0, "WireLead" },
|
|
{ 7, 0, 0, 85, 0, "Solo Vox" },
|
|
{ 4, 0, 24, 85, 0, "SynthAah" },
|
|
{ 4, 0, 64, 85, 0, "VoxLead" },
|
|
{ 7, 0, 0, 86, 0, "Fifth Saw" },
|
|
{ 4, 0, 35, 86, 0, "BigFive" },
|
|
{ 7, 0, 0, 87, 0, "Bass Lead" },
|
|
{ 4, 0, 16, 87, 0, "Big-Low" },
|
|
{ 4, 0, 64, 87, 0, "Fat-Prky" },
|
|
{ 4, 0, 65, 87, 0, "SoftWurl" },
|
|
// Synth Pad
|
|
{ 7, 0, 0, 88, 0, "New Age Pad" },
|
|
{ 4, 0, 64, 88, 0, "Fantasy2" },
|
|
{ 7, 0, 0, 89, 0, "Warm Pad" },
|
|
{ 4, 0, 16, 89, 0, "ThickPad" },
|
|
{ 4, 0, 17, 89, 0, "SoftPad" },
|
|
{ 4, 0, 18, 89, 0, "SinePad" },
|
|
{ 4, 0, 64, 89, 0, "HornPad" },
|
|
{ 4, 0, 65, 89, 0, "RotarStr" },
|
|
{ 7, 0, 0, 90, 0, "Polysynth Pad" },
|
|
{ 4, 0, 64, 90, 0, "PolyPd80" },
|
|
{ 4, 0, 65, 90, 0, "ClickPad" },
|
|
{ 4, 0, 66, 90, 0, "AnaPad" },
|
|
{ 4, 0, 67, 90, 0, "SquarPad" },
|
|
{ 7, 0, 0, 91, 0, "Choir Pad" },
|
|
{ 4, 0, 64, 91, 0, "Heaven2" },
|
|
{ 4, 0, 66, 91, 0, "Itopia" },
|
|
{ 4, 0, 67, 91, 0, "CCPad" },
|
|
{ 4, 0, 65, 91, 0, "LitePad" },
|
|
{ 7, 0, 0, 92, 0, "Bowed Pad" },
|
|
{ 4, 0, 64, 92, 0, "Glacier" },
|
|
{ 4, 0, 65, 92, 0, "GlassPad" },
|
|
{ 7, 0, 0, 93, 0, "Metallic Pad" },
|
|
{ 4, 0, 64, 93, 0, "TinePad" },
|
|
{ 4, 0, 65, 93, 0, "PanPad" },
|
|
{ 7, 0, 0, 94, 0, "Halo Pad" },
|
|
{ 7, 0, 0, 95, 0, "Sweep Pad" },
|
|
{ 4, 0, 20, 95, 0, "Shwimmer" },
|
|
{ 4, 0, 27, 95, 0, "Converge" },
|
|
{ 4, 0, 64, 95, 0, "PolarPad" },
|
|
{ 4, 0, 66, 95, 0, "Celstial" },
|
|
{ 4, 0, 65, 95, 0, "Sweepy" },
|
|
// Synth FX
|
|
{ 7, 0, 0, 96, 0, "Rain" },
|
|
{ 4, 0, 45, 96, 0, "ClaviPad" },
|
|
{ 4, 0, 64, 96, 0, "HrmoRain" },
|
|
{ 4, 0, 65, 96, 0, "AfrcnWnd" },
|
|
{ 4, 0, 66, 96, 0, "Caribean" },
|
|
{ 7, 0, 0, 97, 0, "Soundtrack" },
|
|
{ 4, 0, 27, 97, 0, "Prologue" },
|
|
{ 4, 0, 64, 97, 0, "Ancestrl" },
|
|
{ 4, 0, 65, 97, 0, "Rave" },
|
|
{ 7, 0, 0, 98, 0, "Crystal" },
|
|
{ 4, 0, 12, 98, 0, "SynDrCmp" },
|
|
{ 4, 0, 14, 98, 0, "Popcorn" },
|
|
{ 4, 0, 18, 98, 0, "TinyBell" },
|
|
{ 4, 0, 35, 98, 0, "RndGlock" },
|
|
{ 4, 0, 40, 98, 0, "GlockChi" },
|
|
{ 4, 0, 41, 98, 0, "ClearBel" },
|
|
{ 4, 0, 42, 98, 0, "ChorBell" },
|
|
{ 4, 0, 64, 98, 0, "SynMalet" },
|
|
{ 4, 0, 65, 98, 0, "SftCryst" },
|
|
{ 4, 0, 66, 98, 0, "LoudGlok" },
|
|
{ 4, 0, 67, 98, 0, "XmasBell" },
|
|
{ 4, 0, 68, 98, 0, "VibeBell" },
|
|
{ 4, 0, 69, 98, 0, "DigiBell" },
|
|
{ 4, 0, 70, 98, 0, "AirBells" },
|
|
{ 4, 0, 71, 98, 0, "BellHarp" },
|
|
{ 4, 0, 72, 98, 0, "Gamelmba" },
|
|
{ 7, 0, 0, 99, 0, "Athmosphere" },
|
|
{ 4, 0, 18, 99, 0, "WarmAtms" },
|
|
{ 4, 0, 19, 99, 0, "HollwRls" },
|
|
{ 4, 0, 40, 99, 0, "NylonEP" },
|
|
{ 4, 0, 64, 99, 0, "NylnHarp" },
|
|
{ 4, 0, 65, 99, 0, "HarpVox" },
|
|
{ 7, 0, 0, 100, 0, "Brightness" },
|
|
{ 7, 0, 0, 101, 0, "Goblins" },
|
|
{ 4, 0, 69, 101, 0, "MilkyWay" },
|
|
{ 4, 0, 72, 101, 0, "Puffy" },
|
|
{ 7, 0, 0, 102, 0, "Echoes" },
|
|
{ 7, 0, 0, 103, 0, "Sci-Fi" },
|
|
{ 4, 0, 65, 103, 0, "Odyssey" },
|
|
// Ethnic
|
|
{ 7, 0, 0, 104, 0, "Sitar" },
|
|
{ 4, 0, 32, 104, 0, "DetSitar" },
|
|
{ 4, 0, 35, 104, 0, "Sitar2" },
|
|
{ 4, 0, 96, 104, 0, "Tambra" },
|
|
{ 4, 0, 97, 104, 0, "Tamboura" },
|
|
{ 7, 0, 0, 105, 0, "Banjo" },
|
|
{ 4, 0, 28, 105, 0, "MuteBnjo" },
|
|
{ 4, 0, 96, 105, 0, "Rabab" },
|
|
{ 4, 0, 97, 105, 0, "Gopichnt" },
|
|
{ 4, 0, 98, 105, 0, "Oud" },
|
|
{ 7, 0, 0, 106, 0, "Shamisen" },
|
|
{ 4, 0, 96, 106, 0, "Tsugaru" },
|
|
{ 7, 0, 0, 107, 0, "Koto" },
|
|
{ 4, 0, 96, 107, 0, "T.Koto" },
|
|
{ 4, 0, 97, 107, 0, "Kanoon" },
|
|
{ 7, 0, 0, 108, 0, "Kalimba" },
|
|
{ 4, 0, 64, 108, 0, "BigKalim" },
|
|
{ 7, 0, 0, 109, 0, "Bagpipe" },
|
|
{ 7, 0, 0, 110, 0, "Fiddle" },
|
|
{ 7, 0, 0, 111, 0, "Shanai" },
|
|
{ 4, 0, 64, 111, 0, "Shanai2" },
|
|
{ 4, 0, 96, 111, 0, "Pungi" },
|
|
{ 4, 0, 97, 111, 0, "Hichriki" },
|
|
// Percussive
|
|
{ 7, 0, 0, 112, 0, "Tinkle Bell" },
|
|
{ 4, 0, 96, 112, 0, "Bonang" },
|
|
{ 4, 0, 97, 112, 0, "Gender" },
|
|
{ 4, 0, 98, 112, 0, "Gamelan" },
|
|
{ 4, 0, 99, 112, 0, "S.Gamlan" },
|
|
{ 4, 0, 100, 112, 0, "RamaCym" },
|
|
{ 4, 0, 101, 112, 0, "AsianBel" },
|
|
{ 7, 0, 0, 113, 0, "Agogo" },
|
|
{ 4, 0, 96, 113, 0, "Atrigane" },
|
|
{ 7, 0, 0, 114, 0, "Steel Drums" },
|
|
{ 4, 0, 97, 114, 0, "GlasPerc" },
|
|
{ 4, 0, 98, 114, 0, "ThaiBell" },
|
|
{ 4, 0, 96, 114, 0, "Tablas" },
|
|
{ 7, 0, 0, 115, 0, "Woodblock" },
|
|
{ 4, 0, 96, 115, 0, "Castanet" },
|
|
{ 7, 0, 0, 116, 0, "Taiko Drum" },
|
|
{ 4, 0, 96, 116, 0, "Gr.Cassa" },
|
|
{ 7, 0, 0, 117, 0, "Melodic Drum" },
|
|
{ 4, 0, 64, 117, 0, "MelTom2" },
|
|
{ 4, 0, 65, 117, 0, "RealTom" },
|
|
{ 4, 0, 66, 117, 0, "RockTom" },
|
|
{ 7, 0, 0, 118, 0, "Synth Drum" },
|
|
{ 4, 0, 64, 118, 0, "AnaTom" },
|
|
{ 4, 0, 65, 118, 0, "ElecPerc" },
|
|
{ 7, 0, 0, 119, 0, "Rev. Cymbal" },
|
|
{ 4, 0, 64, 119, 0, "RevCym2" },
|
|
{ 4, 0, 96, 119, 0, "RevSnar1" },
|
|
{ 4, 0, 97, 119, 0, "RevSnar2" },
|
|
{ 4, 0, 98, 119, 0, "RevKick1" },
|
|
{ 4, 0, 99, 119, 0, "RevConBD" },
|
|
{ 4, 0, 100, 119, 0, "RevTom1" },
|
|
{ 4, 0, 101, 119, 0, "RevTom2" },
|
|
// Special FX
|
|
{ 7, 0, 0, 120, 0, "GtrFret Noise" },
|
|
{ 7, 0, 0, 121, 0, "Breath Noise" },
|
|
{ 7, 0, 0, 122, 0, "Seashore" },
|
|
{ 7, 0, 0, 123, 0, "Bird Tweed" },
|
|
{ 7, 0, 0, 124, 0, "Telephone" },
|
|
{ 7, 0, 0, 125, 0, "Helicopter" },
|
|
{ 7, 0, 0, 126, 0, "Applaus" },
|
|
{ 7, 0, 0, 127, 0, "Gunshot" },
|
|
// Drums
|
|
{ 6, 17, 0, 0, 0, "Standard" },
|
|
{ 4, 17, 0, 1, 0, "Standrd2" },
|
|
{ 6, 17, 0, 8, 0, "Room" },
|
|
{ 4, 17, 0, 16, 0, "Rock" },
|
|
{ 6, 17, 0, 24, 0, "Electro" },
|
|
{ 6, 17, 0, 25, 0, "Analog" },
|
|
{ 6, 17, 0, 32, 0, "Jazz" },
|
|
{ 6, 17, 0, 40, 0, "Brush" },
|
|
{ 6, 17, 0, 48, 0, "Classic" },
|
|
{ 2, 17, 0, 16, 0, "Power" },
|
|
{ 2, 17, 0, 56, 0, "SFX1" },
|
|
{ 2, 17, 0, 127, 0, "GM" },
|
|
{ 4, 16, 0, 0, 0, "SFX1" },
|
|
{ 4, 16, 0, 1, 0, "SFX2" },
|
|
{ 4, 4, 0, 0, 0, "CuttngNz" },
|
|
{ 4, 4, 0, 1, 0, "CuttngNz2" },
|
|
{ 4, 4, 0, 3, 0, "StrSlap" },
|
|
{ 4, 4, 0, 16, 0, "Fl.KClik" },
|
|
{ 4, 4, 0, 32, 0, "Rain" },
|
|
{ 4, 4, 0, 33, 0, "Thunder" },
|
|
{ 4, 4, 0, 34, 0, "Wind" },
|
|
{ 4, 4, 0, 35, 0, "Stream" },
|
|
{ 4, 4, 0, 36, 0, "Bubble" },
|
|
{ 4, 4, 0, 37, 0, "Feed" },
|
|
{ 4, 4, 0, 48, 0, "Dog" },
|
|
{ 4, 4, 0, 49, 0, "Horse" },
|
|
{ 4, 4, 0, 50, 0, "Bird2" },
|
|
{ 4, 4, 0, 54, 0, "Ghost" },
|
|
{ 4, 4, 0, 55, 0, "Maou" },
|
|
{ 4, 4, 0, 64, 0, "Tel.Dial" },
|
|
{ 4, 4, 0, 65, 0, "DoorSqek" },
|
|
{ 4, 4, 0, 66, 0, "DoorSlam" },
|
|
{ 4, 4, 0, 67, 0, "Scratch" },
|
|
{ 4, 4, 0, 68, 0, "Scratch2" },
|
|
{ 4, 4, 0, 69, 0, "WindChm" },
|
|
{ 4, 4, 0, 70, 0, "Telphon2" },
|
|
{ 4, 4, 0, 80, 0, "CarEngin" },
|
|
{ 4, 4, 0, 81, 0, "CarStop" },
|
|
{ 4, 4, 0, 82, 0, "CarPass" },
|
|
{ 4, 4, 0, 83, 0, "CarCrash" },
|
|
{ 4, 4, 0, 84, 0, "Siren" },
|
|
{ 4, 4, 0, 85, 0, "Train" },
|
|
{ 4, 4, 0, 86, 0, "Jetplane" },
|
|
{ 4, 4, 0, 87, 0, "Starship" },
|
|
{ 4, 4, 0, 88, 0, "Burst" },
|
|
{ 4, 4, 0, 89, 0, "Coaster" },
|
|
{ 4, 4, 0, 90, 0, "SbMarine" },
|
|
{ 4, 4, 0, 96, 0, "Laughing" },
|
|
{ 4, 4, 0, 97, 0, "Scream" },
|
|
{ 4, 4, 0, 98, 0, "Punch" },
|
|
{ 4, 4, 0, 99, 0, "Heart" },
|
|
{ 4, 4, 0, 100, 0, "FootStep" },
|
|
{ 4, 4, 0, 112, 0, "MchinGun" },
|
|
{ 4, 4, 0, 113, 0, "LaserGun" },
|
|
{ 4, 4, 0, 114, 0, "Xplosion" },
|
|
{ 4, 4, 0, 115, 0, "FireWork" },
|
|
{ 4, 4, 0, 2, 0, "DstCutNz" },
|
|
{ 4, 4, 0, 4, 0, "B.Slide" },
|
|
{ 4, 4, 0, 5, 0, "P.Scrape" },
|
|
{ 4, 4, 0, 51, 0, "Kitty" },
|
|
{ 4, 4, 0, 52, 0, "Growl" },
|
|
{ 4, 4, 0, 53, 0, "Haunted" },
|
|
{ 4, 4, 0, 101, 0, "Applaus2" },
|
|
};
|
|
|
|
//---------------------------------------------------------
|
|
// instrName
|
|
//---------------------------------------------------------
|
|
|
|
static QString instrName(int type, int hbank, int lbank, int program)
|
|
{
|
|
if (program != -1) {
|
|
for (unsigned int i = 0; i < sizeof(minstr)/sizeof(*minstr); ++i) {
|
|
MidiInstrument* mi = &minstr[i];
|
|
if ((mi->patch == program)
|
|
&& (mi->type & type)
|
|
&& (mi->hbank == hbank || hbank == -1)
|
|
&& (mi->lbank == lbank || lbank == -1)) {
|
|
return QString(mi->name);
|
|
}
|
|
}
|
|
}
|
|
return QString();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// processMeta
|
|
//---------------------------------------------------------
|
|
|
|
void MidiFile::processMeta(Score* cs, MidiTrack* track, const Event& mm)
|
|
{
|
|
int tick = mm.ontime();
|
|
Staff* staff = track->staff();
|
|
const uchar* data = (uchar*)mm.edata();
|
|
int staffIdx = track->staffIdx();
|
|
|
|
switch (mm.metaType()) {
|
|
case META_TEXT:
|
|
case META_LYRIC:
|
|
if (staff) {
|
|
QString s((char*)data);
|
|
cs->addLyrics(tick, staffIdx, s);
|
|
}
|
|
break;
|
|
|
|
case META_TRACK_NAME:
|
|
if (staff) {
|
|
QString txt((const char*)data);
|
|
track->setName(txt);
|
|
}
|
|
break;
|
|
|
|
case META_TEMPO:
|
|
{
|
|
unsigned tempo = data[2] + (data[1] << 8) + (data[0] <<16);
|
|
double t = 1000000.0 / double(tempo);
|
|
cs->setTempo(tick, t);
|
|
// TODO: create TempoText
|
|
}
|
|
break;
|
|
|
|
case META_KEY_SIGNATURE:
|
|
if (staff) {
|
|
int key = ((const char*)data)[0];
|
|
if (key < -7 || key > 7) {
|
|
qDebug("ImportMidi: illegal key %d", key);
|
|
break;
|
|
}
|
|
KeySigEvent ks;
|
|
ks.setAccidentalType(key);
|
|
(*staff->keymap())[mm.ontime()] = ks;
|
|
track->setHasKey(true);
|
|
}
|
|
else
|
|
qDebug("meta key: no staff");
|
|
break;
|
|
case META_COMPOSER: // mscore extension
|
|
case META_POET:
|
|
case META_TRANSLATOR:
|
|
case META_SUBTITLE:
|
|
case META_TITLE:
|
|
{
|
|
Text* text = new Text(cs);
|
|
switch(mm.metaType()) {
|
|
case META_COMPOSER:
|
|
case TEXT_TITLE:
|
|
text->setTextStyleType(TEXT_STYLE_COMPOSER);
|
|
break;
|
|
case META_TRANSLATOR:
|
|
text->setTextStyleType(TEXT_STYLE_TRANSLATOR);
|
|
break;
|
|
case META_POET:
|
|
text->setTextStyleType(TEXT_STYLE_POET);
|
|
break;
|
|
case META_SUBTITLE:
|
|
text->setTextStyleType(TEXT_STYLE_SUBTITLE);
|
|
break;
|
|
case META_TITLE:
|
|
text->setTextStyleType(TEXT_STYLE_TITLE);
|
|
break;
|
|
}
|
|
|
|
text->setText((const char*)(mm.edata()));
|
|
|
|
MeasureBase* measure = cs->first();
|
|
if (measure->type() != Element::VBOX) {
|
|
measure = new VBox(cs);
|
|
measure->setTick(0);
|
|
measure->setNext(cs->first());
|
|
cs->add(measure);
|
|
}
|
|
measure->add(text);
|
|
}
|
|
break;
|
|
|
|
case META_COPYRIGHT:
|
|
cs->setMetaTag("Copyright", QString((const char*)(mm.edata())));
|
|
break;
|
|
|
|
case META_TIME_SIGNATURE:
|
|
qDebug("midi: meta timesig: %d, division %d", tick, _division);
|
|
cs->sigmap()->add(tick, Fraction(data[0], 1 << data[1]));
|
|
break;
|
|
|
|
default:
|
|
if (MScore::debugMode)
|
|
qDebug("unknown meta type 0x%02x", mm.metaType());
|
|
break;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// convertMidi
|
|
//---------------------------------------------------------
|
|
|
|
void convertMidi(Score* score, MidiFile* mf)
|
|
{
|
|
mf->separateChannel();
|
|
mf->process1(); // merge noteOn/noteOff into NoteEvent etc.
|
|
mf->changeDivision(MScore::division);
|
|
|
|
/* for (auto is = mf->siglist().begin(); is != mf->siglist().end(); ++is) {
|
|
qDebug(" sig at %d\n", is->first);
|
|
}
|
|
*/
|
|
*(score->sigmap()) = mf->siglist();
|
|
QList<MidiTrack*>* tracks = mf->tracks();
|
|
|
|
//---------------------------------------------------
|
|
// remove empty tracks
|
|
// determine maxPitch/minPitch/medPitch
|
|
// find out instrument
|
|
// build time signature list
|
|
//---------------------------------------------------
|
|
|
|
int staffIdx = 0;
|
|
foreach (MidiTrack* track, *tracks) {
|
|
track->maxPitch = 0;
|
|
track->minPitch = 127;
|
|
track->medPitch = 0;
|
|
track->setProgram(0);
|
|
int events = 0;
|
|
foreach (const Event& e, track->events()) {
|
|
if (e.type() == ME_NOTE) {
|
|
++events;
|
|
int pitch = e.pitch();
|
|
if (pitch > track->maxPitch)
|
|
track->maxPitch = pitch;
|
|
if (pitch < track->minPitch)
|
|
track->minPitch = pitch;
|
|
track->medPitch += pitch;
|
|
}
|
|
else if (e.type() == ME_CONTROLLER && e.controller() == CTRL_PROGRAM) {
|
|
track->setProgram(e.value());
|
|
}
|
|
}
|
|
if (events == 0)
|
|
track->setStaffIdx(-1); // dont create staff for this track
|
|
else {
|
|
track->setStaffIdx(staffIdx++);
|
|
track->medPitch /= events;
|
|
}
|
|
}
|
|
if (staffIdx == 0)
|
|
qDebug("no tracks found");
|
|
|
|
//---------------------------------------------------
|
|
// create instruments
|
|
//---------------------------------------------------
|
|
|
|
int ntracks = tracks->size();
|
|
int idx = 0;
|
|
foreach(MidiTrack* track, *tracks) {
|
|
int staffIdx = track->staffIdx();
|
|
if (staffIdx == -1) {
|
|
track->setStaff(0);
|
|
++idx;
|
|
continue;
|
|
}
|
|
int program = track->getInitProgram();
|
|
track->setProgram(program);
|
|
Part* part = new Part(score);
|
|
|
|
Staff* s = new Staff(score, part, 0);
|
|
part->insertStaff(s);
|
|
score->staves().push_back(s);
|
|
track->setStaff(s);
|
|
|
|
if (track->isDrumTrack()) {
|
|
// s->setClef(0, CLEF_PERC);
|
|
part->instr()->setDrumset(smDrumset);
|
|
}
|
|
else {
|
|
if ((idx < (ntracks-1)) && (tracks->at(idx+1)->outChannel() == track->outChannel()
|
|
&& ((program & 0xff) == 0) && tracks->at(idx+1)->staffIdx() != -1)) {
|
|
// assume that the current track and the next track
|
|
// form a piano part
|
|
Staff* ss = new Staff(score, part, 1);
|
|
part->insertStaff(ss);
|
|
score->staves().push_back(ss);
|
|
|
|
// s->setClef(0, CLEF_G);
|
|
s->setBracket(0, BRACKET_AKKOLADE);
|
|
s->setBracketSpan(0, 2);
|
|
// ss->setClef(0, CLEF_F);
|
|
++idx;
|
|
tracks->at(idx)->setStaff(ss);
|
|
}
|
|
else {
|
|
// ClefType ct = track->medPitch < 58 ? CLEF_F : CLEF_G;
|
|
// s->setClef(0, ct);
|
|
}
|
|
}
|
|
score->appendPart(part);
|
|
++idx;
|
|
}
|
|
|
|
int lastTick = 0;
|
|
foreach (MidiTrack* midiTrack, *tracks) {
|
|
if (midiTrack->staffIdx() == -1)
|
|
continue;
|
|
const EventList el = midiTrack->events();
|
|
if (!el.empty()) {
|
|
auto i = el.end();
|
|
--i;
|
|
if (i->ontime() >lastTick)
|
|
lastTick = i->ontime();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------
|
|
// remove empty measures at beginning
|
|
//---------------------------------------------------
|
|
|
|
int startBar, endBar, beat, tick;
|
|
score->sigmap()->tickValues(lastTick, &endBar, &beat, &tick);
|
|
if (beat || tick)
|
|
++endBar;
|
|
|
|
for (startBar = 0; startBar < endBar; ++startBar) {
|
|
int tick1 = score->sigmap()->bar2tick(startBar, 0);
|
|
int tick2 = score->sigmap()->bar2tick(startBar + 1, 0);
|
|
int events = 0;
|
|
foreach (MidiTrack* midiTrack, *tracks) {
|
|
if (midiTrack->staffIdx() == -1)
|
|
continue;
|
|
foreach(const Event ev, midiTrack->events()) {
|
|
int t = ev.ontime();
|
|
if (t >= tick2)
|
|
break;
|
|
if (t < tick1)
|
|
continue;
|
|
if (ev.type() == ME_NOTE) {
|
|
++events;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (events)
|
|
break;
|
|
}
|
|
tick = score->sigmap()->bar2tick(startBar, 0);
|
|
if (tick)
|
|
qDebug("remove empty measures %d ticks, startBar %d", tick, startBar);
|
|
mf->move(-tick);
|
|
|
|
//---------------------------------------------------
|
|
// count measures
|
|
//---------------------------------------------------
|
|
|
|
lastTick = 0;
|
|
int xx = 0;
|
|
foreach (MidiTrack* midiTrack, *tracks) {
|
|
if (midiTrack->staffIdx() == -1)
|
|
continue;
|
|
++xx;
|
|
const EventList el = midiTrack->events();
|
|
for (auto ie = el.begin(); ie != el.end(); ++ie) {
|
|
if (ie->type() != ME_NOTE)
|
|
continue;
|
|
int tick = ie->ontime() + ie->duration();
|
|
if (tick > lastTick)
|
|
lastTick = tick;
|
|
}
|
|
}
|
|
int bars;
|
|
score->sigmap()->tickValues(lastTick, &bars, &beat, &tick);
|
|
if (beat > 0 || tick > 0)
|
|
++bars;
|
|
|
|
//---------------------------------------------------
|
|
// create measures
|
|
//---------------------------------------------------
|
|
|
|
for (int i = 0; i < bars; ++i) {
|
|
Measure* measure = new Measure(score);
|
|
int tick = score->sigmap()->bar2tick(i, 0);
|
|
measure->setTick(tick);
|
|
Fraction ts(score->sigmap()->timesig(tick).timesig());
|
|
measure->setTimesig(ts);
|
|
measure->setLen(ts);
|
|
|
|
score->add(measure);
|
|
}
|
|
score->fixTicks();
|
|
|
|
foreach (MidiTrack* midiTrack, *tracks) {
|
|
if (midiTrack->staffIdx() == -1)
|
|
continue;
|
|
midiTrack->cleanup(); // quantize
|
|
}
|
|
|
|
//---------------------------------------------------
|
|
// process meta events
|
|
//---------------------------------------------------
|
|
|
|
foreach (MidiTrack* track, *tracks) {
|
|
foreach (Event e, track->events()) {
|
|
if ((e.type() == ME_META) && (e.metaType() != META_LYRIC))
|
|
mf->processMeta(score, track, e);
|
|
}
|
|
if (MScore::debugMode) {
|
|
qDebug("Track %2d:%2d key %d <%s><%s>", track->outChannel(),
|
|
track->outPort(), track->hasKey(), qPrintable(track->name()),
|
|
qPrintable(track->comment()));
|
|
}
|
|
|
|
Part* part = track->staff() ? track->staff()->part() : 0;
|
|
if (part) {
|
|
int program = track->program();
|
|
if (track->name().isEmpty()) {
|
|
int hbank = -1, lbank = -1;
|
|
if (program == -1)
|
|
program = 0;
|
|
else {
|
|
hbank = (program >> 16);
|
|
lbank = (program >> 8) & 0xff;
|
|
program = program & 0xff;
|
|
}
|
|
QString t(instrName(mf->midiType(), hbank, lbank, program));
|
|
if (!t.isEmpty())
|
|
part->setLongName(t);
|
|
}
|
|
else
|
|
part->setLongName(track->name());
|
|
part->setPartName(part->longName().toPlainText());
|
|
part->setMidiChannel(track->outChannel());
|
|
part->setMidiProgram(track->program() & 0x7f); // only GM
|
|
}
|
|
if (track->staffIdx() != -1)
|
|
mf->convertTrack(score, track);
|
|
|
|
foreach (Event e, track->events()) {
|
|
if ((e.type() == ME_META) && (e.metaType() == META_LYRIC))
|
|
mf->processMeta(score, track, e);
|
|
}
|
|
}
|
|
|
|
for (auto is = score->sigmap()->begin(); is != score->sigmap()->end(); ++is) {
|
|
SigEvent se = is->second;
|
|
int tick = is->first;
|
|
Measure* m = score->tick2measure(tick);
|
|
if (!m)
|
|
continue;
|
|
for (int staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
|
|
TimeSig* ts = new TimeSig(score);
|
|
ts->setSig(se.timesig());
|
|
ts->setTrack(staffIdx * VOICES);
|
|
Segment* seg = m->getSegment(ts, tick);
|
|
seg->add(ts);
|
|
}
|
|
}
|
|
score->connectTies();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// MNote
|
|
// special Midi Note
|
|
//---------------------------------------------------------
|
|
|
|
struct MNote {
|
|
Event mc;
|
|
QList<Tie*> ties;
|
|
|
|
MNote(const Event& _mc) : mc(_mc) {
|
|
for (int i = 0; i < mc.notes().size(); ++i)
|
|
ties.append(0);
|
|
}
|
|
};
|
|
|
|
//---------------------------------------------------------
|
|
// convertTrack
|
|
//---------------------------------------------------------
|
|
|
|
void MidiFile::convertTrack(Score* score, MidiTrack* midiTrack)
|
|
{
|
|
int key = 0; // TODO-LIB findKey(midiTrack, score->sigmap());
|
|
int staffIdx = midiTrack->staffIdx();
|
|
midiTrack->findChords();
|
|
|
|
int voices = midiTrack->separateVoices(2);
|
|
Staff* cstaff = midiTrack->staff();
|
|
const EventList el = midiTrack->events();
|
|
Drumset* drumset = cstaff->part()->instr()->drumset();
|
|
bool useDrumset = cstaff->part()->instr()->useDrumset();
|
|
KeyList* km = cstaff->keymap();
|
|
|
|
for (int voice = 0; voice < voices; ++voice) {
|
|
QList<MNote*> notes;
|
|
int ctick = 0;
|
|
for (auto i = el.begin(); i != el.end();) {
|
|
Event e = *i;
|
|
if (e.type() != ME_CHORD || e.voice() != voice) {
|
|
++i;
|
|
continue;
|
|
}
|
|
//
|
|
// process pending notes
|
|
//
|
|
while (!notes.isEmpty()) {
|
|
int tick = notes[0]->mc.ontime();
|
|
int len = i->ontime() - tick;
|
|
if (len <= 0)
|
|
break;
|
|
foreach (MNote* n, notes) {
|
|
if ((n->mc.duration() < len) && (n->mc.duration() != 0))
|
|
len = n->mc.duration();
|
|
}
|
|
Measure* measure = score->tick2measure(tick);
|
|
// split notes on measure boundary
|
|
if ((tick + len) > measure->tick() + measure->ticks())
|
|
len = measure->tick() + measure->ticks() - tick;
|
|
QList<TDuration> dl = toDurationList(Fraction::fromTicks(len), false);
|
|
if (dl.isEmpty())
|
|
break;
|
|
TDuration d = dl[0];
|
|
len = d.ticks();
|
|
|
|
Chord* chord = new Chord(score);
|
|
chord->setTrack(staffIdx * VOICES + voice);
|
|
chord->setDurationType(d);
|
|
chord->setDuration(d.fraction());
|
|
Segment* s = measure->getSegment(chord, tick);
|
|
s->add(chord);
|
|
chord->setUserPlayEvents(true);
|
|
|
|
int actualTicks = chord->actualTicks();
|
|
foreach (MNote* n, notes) {
|
|
QList<Event>& nl = n->mc.notes();
|
|
for (int i = 0; i < nl.size(); ++i) {
|
|
Event mn = nl[i];
|
|
Note* note = new Note(score);
|
|
|
|
// TODO - does this need to be key-aware?
|
|
note->setPitch(mn.pitch(), pitch2tpc(mn.pitch(), KEY_C, PREFER_NEAREST));
|
|
chord->add(note);
|
|
note->setVeloType(MScore::USER_VAL);
|
|
note->setVeloOffset(mn.velo());
|
|
|
|
NoteEventList el;
|
|
el.append(NoteEvent(
|
|
0,
|
|
(mn.noquantOntime() - tick) * 1000 / actualTicks,
|
|
mn.noquantDuration() * 1000 / actualTicks
|
|
));
|
|
note->setPlayEvents(el);
|
|
|
|
if (useDrumset) {
|
|
if (!drumset->isValid(mn.pitch())) {
|
|
qDebug("unmapped drum note 0x%02x %d", mn.pitch(), mn.pitch());
|
|
}
|
|
else {
|
|
chord->setStemDirection(drumset->stemDirection(mn.pitch()));
|
|
}
|
|
}
|
|
|
|
if (n->ties[i]) {
|
|
n->ties[i]->setEndNote(note);
|
|
n->ties[i]->setTrack(note->track());
|
|
note->setTieBack(n->ties[i]);
|
|
// note->setOnTimeOffset(0);
|
|
// note->setOnTimeUserOffset(0);
|
|
}
|
|
}
|
|
if (n->mc.duration() <= len) {
|
|
notes.removeAt(notes.indexOf(n));
|
|
continue;
|
|
}
|
|
for (int i = 0; i < nl.size(); ++i) {
|
|
Event mn = nl[i];
|
|
Note* note = chord->findNote(mn.pitch());
|
|
n->ties[i] = new Tie(score);
|
|
n->ties[i]->setStartNote(note);
|
|
// note->setOffTimeOffset(0);
|
|
// note->setOffTimeUserOffset(0);
|
|
note->setTieFor(n->ties[i]);
|
|
}
|
|
n->mc.setOntime(n->mc.ontime() + len);
|
|
n->mc.setDuration(n->mc.duration() - len);
|
|
}
|
|
ctick += len;
|
|
}
|
|
//
|
|
// check for gap and fill with rest
|
|
//
|
|
int restLen = i->ontime() - ctick;
|
|
if (voice == 0) {
|
|
while (restLen > 0) {
|
|
int len = restLen;
|
|
Measure* measure = score->tick2measure(ctick);
|
|
if (ctick >= measure->tick() + measure->ticks()) {
|
|
qDebug("tick2measure: %d end of score?", ctick);
|
|
ctick += restLen;
|
|
restLen = 0;
|
|
break;
|
|
}
|
|
// split rest on measure boundary
|
|
if ((ctick + len) > measure->tick() + measure->ticks())
|
|
len = measure->tick() + measure->ticks() - ctick;
|
|
if (len >= measure->ticks()) {
|
|
len = measure->ticks();
|
|
TDuration d(TDuration::V_MEASURE);
|
|
Rest* rest = new Rest(score, d);
|
|
rest->setDuration(measure->len());
|
|
rest->setTrack(staffIdx * VOICES);
|
|
Segment* s = measure->getSegment(rest, ctick);
|
|
s->add(rest);
|
|
restLen -= len;
|
|
ctick += len;
|
|
}
|
|
else {
|
|
QList<TDuration> dl = toDurationList(Fraction::fromTicks(len), false);
|
|
if (dl.size() == 0) {
|
|
qDebug("cannot create duration list for len %d", len);
|
|
restLen = 0; // fake
|
|
break;
|
|
}
|
|
foreach (TDuration d, dl) {
|
|
Rest* rest = new Rest(score, d);
|
|
rest->setDuration(d.fraction());
|
|
rest->setTrack(staffIdx * VOICES);
|
|
Segment* s = measure->getSegment(Segment::SegChordRest, ctick);
|
|
s->add(rest);
|
|
restLen -= d.ticks();
|
|
ctick += d.ticks();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
ctick += restLen;
|
|
|
|
//
|
|
// collect all notes on current
|
|
// tick position
|
|
//
|
|
for (;i != el.end(); ++i) {
|
|
Event e = *i;
|
|
if (e.type() != ME_CHORD)
|
|
continue;
|
|
if (i->ontime() != ctick)
|
|
break;
|
|
if (e.voice() != voice)
|
|
continue;
|
|
MNote* n = new MNote(e);
|
|
notes.append(n);
|
|
}
|
|
if (notes.isEmpty())
|
|
break;
|
|
}
|
|
//
|
|
// process pending notes
|
|
//
|
|
Measure* measure = 0;
|
|
while (!notes.isEmpty()) {
|
|
int tick = notes[0]->mc.ontime();
|
|
measure = score->tick2measure(tick);
|
|
if (tick >= measure->tick() + measure->ticks()) {
|
|
qDebug("=======================EOM");
|
|
break;
|
|
}
|
|
|
|
Chord* chord = new Chord(score);
|
|
chord->setTrack(staffIdx * VOICES + voice);
|
|
Segment* s = measure->getSegment(chord, tick);
|
|
s->add(chord);
|
|
int len = INT_MAX;
|
|
foreach (MNote* n, notes) {
|
|
if (n->mc.duration() < len)
|
|
len = n->mc.duration();
|
|
}
|
|
if (len == 0) {
|
|
qDebug("ImportMidi: note len zero");
|
|
abort();
|
|
}
|
|
// split notes on measure boundary
|
|
// qDebug("tick %d len %d = %d mt %d mtl %d = %d",
|
|
// tick, len, tick+len, measure->tick(), measure->ticks(), measure->tick()+measure->ticks());
|
|
if ((tick + len) > measure->tick() + measure->ticks()) {
|
|
len = measure->tick() + measure->ticks() - tick;
|
|
if (len == 0) {
|
|
qDebug("ImportMidi2: note len zero");
|
|
abort();
|
|
}
|
|
}
|
|
QList<TDuration> dl = toDurationList(Fraction::fromTicks(len), false);
|
|
TDuration d = dl.front();
|
|
len = d.ticks();
|
|
chord->setDurationType(d);
|
|
chord->setDuration(d.fraction());
|
|
ctick += len;
|
|
chord->setUserPlayEvents(true);
|
|
|
|
int actualTicks = chord->actualTicks();
|
|
foreach (MNote* n, notes) {
|
|
const QList<Event>& nl = n->mc.notes();
|
|
for (int i = 0; i < nl.size(); ++i) {
|
|
const Event& mn = nl[i];
|
|
Note* note = new Note(score);
|
|
note->setPitch(mn.pitch(), mn.tpc());
|
|
chord->add(note);
|
|
note->setVeloType(MScore::USER_VAL);
|
|
note->setVeloOffset(mn.velo());
|
|
|
|
NoteEventList el;
|
|
el.append(NoteEvent(
|
|
0,
|
|
(mn.noquantOntime() - tick) * 1000 / actualTicks,
|
|
mn.noquantDuration() * 1000 / actualTicks
|
|
));
|
|
note->setPlayEvents(el);
|
|
|
|
if (n->ties[i]) {
|
|
n->ties[i]->setEndNote(note);
|
|
n->ties[i]->setTrack(note->track());
|
|
note->setTieBack(n->ties[i]);
|
|
}
|
|
}
|
|
if (n->mc.duration() <= len) {
|
|
notes.removeAt(notes.indexOf(n));
|
|
continue;
|
|
}
|
|
n->mc.setDuration(n->mc.duration() - len);
|
|
n->mc.setOntime(n->mc.ontime() + len);
|
|
|
|
for (int i = 0; i < nl.size(); ++i) {
|
|
const Event& mn = nl[i];
|
|
Note* note = chord->findNote(mn.pitch());
|
|
n->ties[i] = new Tie(score);
|
|
n->ties[i]->setStartNote(note);
|
|
note->setTieFor(n->ties[i]);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// check for gap and fill with rest
|
|
//
|
|
measure = score->lastMeasure();
|
|
int restLen = measure ? (measure->tick() + measure->ticks() - ctick) : 0;
|
|
while (restLen > 0 && voice == 0) {
|
|
Measure* measure = score->tick2measure(ctick);
|
|
int ticks = measure->tick() + measure->ticks() - ctick;
|
|
|
|
QList<TDuration> dl = toDurationList(Fraction::fromTicks(ticks), false);
|
|
foreach(TDuration d, dl) {
|
|
Rest* rest;
|
|
if (d.fraction() == measure->len())
|
|
rest = new Rest(score, TDuration::V_MEASURE);
|
|
else
|
|
rest = new Rest(score, d);
|
|
rest->setDuration(d.fraction());
|
|
rest->setTrack(staffIdx * VOICES + voice);
|
|
Segment* s = measure->getSegment(rest, ctick);
|
|
s->add(rest);
|
|
int ticks2 = d.ticks();
|
|
restLen -= ticks2;
|
|
ctick += ticks2;
|
|
}
|
|
}
|
|
}
|
|
if (!midiTrack->hasKey() && !midiTrack->isDrumTrack()) {
|
|
KeySigEvent ks;
|
|
ks.setAccidentalType(key);
|
|
(*km)[0] = ks;
|
|
}
|
|
for (auto i = km->begin(); i != km->end(); ++i) {
|
|
int tick = i->first;
|
|
KeySigEvent key = i->second;
|
|
KeySig* ks = new KeySig(score);
|
|
ks->setTrack(staffIdx * VOICES);
|
|
ks->setGenerated(false);
|
|
ks->setKeySigEvent(key);
|
|
ks->setMag(cstaff->mag());
|
|
Measure* m = score->tick2measure(tick);
|
|
Segment* seg = m->getSegment(ks, tick);
|
|
seg->add(ks);
|
|
}
|
|
#if 0 // TODO
|
|
ClefList* cl = cstaff->clefList();
|
|
for (ciClefEvent i = cl->begin(); i != cl->end(); ++i) {
|
|
int tick = i.key();
|
|
Clef* clef = new Clef(score);
|
|
clef->setClefType(i.value());
|
|
clef->setTrack(staffIdx * VOICES);
|
|
clef->setGenerated(false);
|
|
clef->setMag(cstaff->mag());
|
|
Measure* m = score->tick2measure(tick);
|
|
Segment* seg = m->getSegment(clef, tick);
|
|
seg->add(clef);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// importMidi
|
|
// return true on success
|
|
//---------------------------------------------------------
|
|
|
|
Score::FileError importMidi(Score* score, const QString& name)
|
|
{
|
|
if (name.isEmpty())
|
|
return Score::FILE_NOT_FOUND;
|
|
QFile fp(name);
|
|
if (!fp.open(QIODevice::ReadOnly))
|
|
return Score::FILE_OPEN_ERROR;;
|
|
MidiFile mf;
|
|
try {
|
|
mf.read(&fp);
|
|
}
|
|
catch(QString errorText) {
|
|
if (!noGui) {
|
|
QMessageBox::warning(0,
|
|
QWidget::tr("MuseScore: load midi"),
|
|
QWidget::tr("Load failed: ") + errorText,
|
|
QString::null, QWidget::tr("Quit"), QString::null, 0, 1);
|
|
}
|
|
fp.close();
|
|
return Score::FILE_BAD_FORMAT;
|
|
}
|
|
fp.close();
|
|
|
|
mf.setShortestNote(preferences.shortestNote);
|
|
|
|
convertMidi(score, &mf);
|
|
return Score::FILE_NO_ERROR;
|
|
}
|
|
|