2
* midi_import.cpp - support for importing MIDI-files
4
* Copyright (c) 2005-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
6
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
8
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU General Public
10
* License as published by the Free Software Foundation; either
11
* version 2 of the License, or (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* General Public License for more details.
18
* You should have received a copy of the GNU General Public
19
* License along with this program (see COPYING); if not, write to the
20
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21
* Boston, MA 02110-1301 USA.
26
#include <QtXml/QDomDocument>
27
#include <QtCore/QDir>
28
#include <QtGui/QApplication>
29
#include <QtGui/QMessageBox>
30
#include <QtGui/QProgressDialog>
32
#include "midi_import.h"
33
#include "track_container.h"
34
#include "instrument_track.h"
35
#include "automation_track.h"
36
#include "automation_pattern.h"
37
#include "config_mgr.h"
39
#include "instrument.h"
40
#include "main_window.h"
45
#include "portsmf/allegro.h"
47
#define makeID(_c0, _c1, _c2, _c3) \
49
( ( _c0 ) | ( ( _c1 ) << 8 ) | ( ( _c2 ) << 16 ) | ( ( _c3 ) << 24 ) ) )
56
plugin::descriptor PLUGIN_EXPORT midiimport_plugin_descriptor =
58
STRINGIFY( PLUGIN_NAME ),
60
QT_TRANSLATE_NOOP( "pluginBrowser",
61
"Filter for importing MIDI-files into LMMS" ),
62
"Tobias Doerffel <tobydox/at/users/dot/sf/dot/net>",
73
midiImport::midiImport( const QString & _file ) :
74
importFilter( _file, &midiimport_plugin_descriptor ),
83
midiImport::~midiImport()
90
bool midiImport::tryImport( trackContainer * _tc )
92
if( openFile() == FALSE )
97
#ifdef LMMS_HAVE_FLUIDSYNTH
98
if( engine::hasGUI() &&
99
configManager::inst()->defaultSoundfont().isEmpty() )
101
QMessageBox::information( engine::getMainWindow(),
102
tr( "Setup incomplete" ),
103
tr( "You do not have set up a default soundfont in "
104
"the settings dialog (Edit->Settings). "
105
"Therefore no sound will be played back after "
106
"importing this MIDI file. You should download "
107
"a General MIDI soundfont, specify it in "
108
"settings dialog and try again." ) );
111
if( engine::hasGUI() )
113
QMessageBox::information( engine::getMainWindow(),
114
tr( "Setup incomplete" ),
115
tr( "You did not compile LMMS with support for "
116
"SoundFont2 player, which is used to add default "
117
"sound to imported MIDI files. "
118
"Therefore no sound will be played back after "
119
"importing this MIDI file." ) );
125
case makeID( 'M', 'T', 'h', 'd' ):
126
printf( "midiImport::tryImport(): found MThd\n");
127
return( readSMF( _tc ) );
129
case makeID( 'R', 'I', 'F', 'F' ):
130
printf( "midiImport::tryImport(): found RIFF\n");
131
return( readRIFF( _tc ) );
134
printf( "midiImport::tryImport(): not a Standard MIDI "
153
automationTrack * at;
154
automationPattern * ap;
157
smfMidiCC & create( trackContainer * _tc )
161
at = dynamic_cast<automationTrack *>(
162
track::create( track::AutomationTrack, _tc ) );
176
smfMidiCC & putValue( midiTime time, automatableModel * objModel, float value )
178
if( !ap || time > lastPos + DefaultTicksPerTact )
180
midiTime pPos = midiTime( time.getTact(), 0 );
181
ap = dynamic_cast<automationPattern*>(
183
ap->movePosition( pPos );
185
ap->addObject( objModel );
188
time = time - ap->startPosition();
189
ap->putValue( time, value, false );
190
ap->changeLength( midiTime( time.getTact() + 1, 0 ) );
211
instrumentTrack * it;
213
instrument * it_inst;
218
smfMidiChannel * create( trackContainer * _tc )
221
it = dynamic_cast<instrumentTrack *>(
222
track::create( track::InstrumentTrack, _tc ) );
224
#ifdef LMMS_HAVE_FLUIDSYNTH
225
it_inst = it->loadInstrument( "sf2player" );
230
it_inst->loadFile( configManager::inst()->defaultSoundfont() );
231
it_inst->getChildModel( "bank" )->setValue( 0 );
232
it_inst->getChildModel( "patch" )->setValue( 0 );
236
it_inst = it->loadInstrument( "patman" );
239
it_inst = it->loadInstrument( "patman" );
248
void addNote( note & n )
250
if( !p || n.pos() > lastEnd + DefaultTicksPerTact )
252
midiTime pPos = midiTime(n.pos().getTact(), 0 );
253
p = dynamic_cast<pattern *>( it->createTCO( 0 ) );
254
p->movePosition( pPos );
257
lastEnd = n.pos() + n.length();
258
n.setPos( n.pos( p->startPosition() ) );
259
p->addNote( n, false );
265
bool midiImport::readSMF( trackContainer * _tc )
267
QString filename = file().fileName();
270
const int preTrackSteps = 2;
271
QProgressDialog pd( trackContainer::tr( "Importing MIDI-file..." ),
272
trackContainer::tr( "Cancel" ), 0, preTrackSteps, engine::getMainWindow() );
273
pd.setWindowTitle( trackContainer::tr( "Please wait..." ) );
274
pd.setWindowModality(Qt::WindowModal);
275
pd.setMinimumDuration( 0 );
279
Alg_seq_ptr seq = new Alg_seq(filename.toLocal8Bit(), true);
280
seq->convert_to_beats();
282
pd.setMaximum( seq->tracks() + preTrackSteps );
285
// 128 CC + Pitch Bend
287
smfMidiChannel chs[256];
289
meterModel & timeSigMM = engine::getSong()->getTimeSigModel();
290
automationPattern * timeSigNumeratorPat =
291
automationPattern::globalAutomationPattern( &timeSigMM.numeratorModel() );
292
automationPattern * timeSigDenominatorPat =
293
automationPattern::globalAutomationPattern( &timeSigMM.denominatorModel() );
295
// TODO: adjust these to Time.Sig changes
296
double beatsPerTact = 4;
297
double ticksPerBeat = DefaultTicksPerTact / beatsPerTact;
300
Alg_time_sigs * timeSigs = &seq->time_sig;
301
for( int s = 0; s < timeSigs->length(); ++s )
303
Alg_time_sig timeSig = (*timeSigs)[s];
304
// Initial timeSig, set song-default value
305
if(/* timeSig.beat == 0*/ true )
307
// TODO set song-global default value
308
printf("Another timesig at %f\n", timeSig.beat);
309
timeSigNumeratorPat->putValue( timeSig.beat*ticksPerBeat, timeSig.num );
310
timeSigDenominatorPat->putValue( timeSig.beat*ticksPerBeat, timeSig.den );
321
automationPattern * tap = _tc->tempoAutomationPattern();
325
Alg_time_map * timeMap = seq->get_time_map();
326
Alg_beats & beats = timeMap->beats;
327
for( int i = 0; i < beats.len - 1; i++ )
329
Alg_beat_ptr b = &(beats[i]);
330
double tempo = ( beats[i + 1].beat - b->beat ) /
331
( beats[i + 1].time - beats[i].time );
332
tap->putValue( b->beat * ticksPerBeat, tempo * 60.0 );
334
if( timeMap->last_tempo_flag )
336
Alg_beat_ptr b = &( beats[beats.len - 1] );
337
tap->putValue( b->beat * ticksPerBeat, timeMap->last_tempo * 60.0 );
342
for( int e = 0; e < seq->length(); ++e )
344
Alg_event_ptr evt = (*seq)[e];
346
if( evt->is_update() )
348
printf("Unhandled SONG update: %d %f %s\n",
349
evt->get_type_code(), evt->time, evt->get_attribute() );
354
for( int t = 0; t < seq->tracks(); ++t )
356
Alg_track_ptr trk = seq->track( t );
357
pd.setValue( t + preTrackSteps );
359
for( int c = 0; c < 129; c++ )
364
// Now look at events
365
for( int e = 0; e < trk->length(); ++e )
367
Alg_event_ptr evt = (*trk)[e];
369
if( evt->chan == -1 )
371
printf("MISSING GLOBAL THINGY\n");
372
printf(" %d %d %f %s\n", (int) evt->chan,
373
evt->get_type_code(), evt->time,
374
evt->get_attribute() );
377
else if( evt->is_note() && evt->chan < 256 )
379
smfMidiChannel * ch = chs[evt->chan].create( _tc );
380
Alg_note_ptr noteEvt = dynamic_cast<Alg_note_ptr>( evt );
382
note n( noteEvt->get_duration() * ticksPerBeat,
383
noteEvt->get_start_time() * ticksPerBeat,
384
noteEvt->get_identifier() - 12,
385
noteEvt->get_loud());
390
else if( evt->is_update() )
392
smfMidiChannel * ch = chs[evt->chan].create( _tc );
394
double time = evt->time*ticksPerBeat;
395
QString update( evt->get_attribute() );
397
if( update == "programi" )
399
long prog = evt->get_integer_value();
402
ch->it_inst->getChildModel( "bank" )->setValue( 0 );
403
ch->it_inst->getChildModel( "patch" )->setValue( prog );
406
const QString num = QString::number( prog );
407
const QString filter = QString().fill( '0', 3 - num.length() ) + num + "*.pat";
408
const QString dir = "/usr/share/midi/"
409
"freepats/Tone_000/";
410
const QStringList files = QDir( dir ).
411
entryList( QStringList( filter ) );
412
if( ch->it_inst && !files.empty() )
414
ch->it_inst->loadFile( dir+files.front() );
418
else if( update == "tracknames" )
420
QString trackName( evt->get_string_value() );
421
ch->it->setName( trackName );
422
//ch.p->setName( trackName );
425
else if( update.startsWith( "control" ) || update == "bendr" )
427
int ccid = update.mid( 7, update.length()-8 ).toInt();
428
if( update == "bendr" )
434
double cc = evt->get_real_value();
435
automatableModel * objModel = NULL;
440
if( ch->isSF2 && ch->it_inst )
442
objModel = ch->it_inst->getChildModel( "bank" );
443
printf("BANK SELECT %f %d\n", cc, (int)(cc*127.0));
449
objModel = ch->it->volumeModel();
454
objModel = ch->it->panningModel();
455
cc = cc * 200.f - 100.0f;
459
objModel = ch->it->pitchModel();
466
if( time == 0 && objModel )
468
objModel->setInitValue( cc );
472
ccs[ccid].create( _tc );
473
ccs[ccid].putValue( time, objModel, cc );
479
printf("Unhandled update: %d %d %f %s\n", (int) evt->chan,
480
evt->get_type_code(), evt->time, evt->get_attribute() );
489
for( int c=0; c < 256; ++c )
491
if( !chs[c].hasNotes && chs[c].it )
493
printf(" Should remove empty track\n");
494
// must delete trackView first - but where is it?
495
//_tc->removeTrack( chs[c].it );
506
bool midiImport::readRIFF( trackContainer * _tc )
511
// check file type ("RMID" = RIFF MIDI)
512
if( readID() != makeID( 'R', 'M', 'I', 'D' ) )
515
printf( "midiImport::readRIFF(): invalid file format\n" );
518
// search for "data" chunk
522
int len = read32LE();
526
printf( "midiImport::readRIFF(): data chunk not "
530
if( id == makeID( 'd', 'a', 't', 'a' ) )
538
skip( ( len + 1 ) & ~1 );
540
// the "data" chunk must contain data in SMF format
541
if( readID() != makeID( 'M', 'T', 'h', 'd' ) )
545
return( readSMF( _tc ) );
551
void midiImport::error( void )
553
printf( "midiImport::readTrack(): invalid MIDI data (offset %#x)\n",
554
(unsigned int) file().pos() );
562
// neccessary for getting instance out of shared lib
563
plugin * PLUGIN_EXPORT lmms_plugin_main( model *, void * _data )
565
return( new midiImport( static_cast<const char *>( _data ) ) );