mirror of
https://github.com/LMMS/lmms.git
synced 2026-01-25 23:08:12 -05:00
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@547 0778d3d1-df1d-0410-868b-ea421aaaa00d
957 lines
21 KiB
C++
957 lines
21 KiB
C++
/*
|
|
* flp_import.cpp - support for importing FLP-files
|
|
*
|
|
* Copyright (c) 2006-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
|
*
|
|
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
|
*
|
|
* This program 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 2 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 (see COPYING); if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA.
|
|
*
|
|
*/
|
|
|
|
|
|
#include <Qt/QtXml>
|
|
#include <QtGui/QApplication>
|
|
#include <QtGui/QProgressDialog>
|
|
#include <QtCore/QDir>
|
|
#include <QtCore/QBuffer>
|
|
|
|
#include "flp_import.h"
|
|
#include "arp_and_chords_tab_widget.h"
|
|
#include "basic_filters.h"
|
|
#include "bb_editor.h"
|
|
#include "bb_track.h"
|
|
#include "combobox.h"
|
|
#include "config_mgr.h"
|
|
#include "debug.h"
|
|
#include "engine.h"
|
|
#include "envelope_tab_widget.h"
|
|
#include "envelope_and_lfo_widget.h"
|
|
#include "group_box.h"
|
|
#include "instrument.h"
|
|
#include "instrument_track.h"
|
|
#include "knob.h"
|
|
#include "oscillator.h"
|
|
#include "pattern.h"
|
|
#include "piano_widget.h"
|
|
#include "project_journal.h"
|
|
#include "project_notes.h"
|
|
#include "song_editor.h"
|
|
#include "tempo_sync_knob.h"
|
|
#include "track_container.h"
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_CTYPE_H
|
|
#include <ctype.h>
|
|
#endif
|
|
|
|
#define makeID(_c0, _c1, _c2, _c3) \
|
|
( ( _c0 ) | ( ( _c1 ) << 8 ) | ( ( _c2 ) << 16 ) | ( ( _c3 ) << 24 ) )
|
|
|
|
|
|
extern "C"
|
|
{
|
|
|
|
plugin::descriptor flpimport_plugin_descriptor =
|
|
{
|
|
STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ),
|
|
"FLP Import",
|
|
QT_TRANSLATE_NOOP( "pluginBrowser",
|
|
"Filter for importing FL Studio projects into LMMS" ),
|
|
"Tobias Doerffel <tobydox/at/users/dot/sf/dot/net>",
|
|
0x0100,
|
|
plugin::ImportFilter,
|
|
new QPixmap(),
|
|
NULL
|
|
} ;
|
|
|
|
|
|
|
|
// unrtf-stuff
|
|
#include "defs.h"
|
|
#include "main.h"
|
|
#include "html.h"
|
|
#include "word.h"
|
|
#include "hash.h"
|
|
#include "convert.h"
|
|
#include "attr.h"
|
|
|
|
|
|
OutputPersonality * op = NULL;
|
|
int lineno = 0;
|
|
#define inline_mode 0
|
|
#define debug_mode 0
|
|
#define nopict_mode 1
|
|
#define verbose_mode 0
|
|
#define simple_mode 0
|
|
|
|
extern QString outstring;
|
|
|
|
}
|
|
|
|
|
|
static void dump_mem( const void * buffer, uint n_bytes )
|
|
{
|
|
uchar * cp = (uchar *) buffer;
|
|
for( uint k = 0; k < n_bytes; ++k )
|
|
{
|
|
printf( "%02x ", (unsigned int)cp[k] );//( cp[k] > 31 || cp[k] < 7 ) ? cp[k] : '.' );
|
|
}
|
|
printf( "\n" );
|
|
}
|
|
|
|
|
|
|
|
flpImport::flpImport( const QString & _file ) :
|
|
importFilter( _file, &flpimport_plugin_descriptor )
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
flpImport::~flpImport()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
bool flpImport::tryImport( trackContainer * _tc )
|
|
{
|
|
if( openFile() == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if( readID() != makeID( 'F', 'L', 'h', 'd' ) )
|
|
{
|
|
printf( "flpImport::tryImport(): not a valid FL project\n" );
|
|
return( FALSE );
|
|
}
|
|
|
|
const int header_len = read32LE();
|
|
if( header_len != 6 )
|
|
{
|
|
printf( "flpImport::tryImport(): invalid file format\n" );
|
|
return( FALSE );
|
|
}
|
|
|
|
const int type = read16LE();
|
|
if( type != 0 )
|
|
{
|
|
printf( "flpImport::tryImport(): type %d format is not "
|
|
"supported\n", type );
|
|
return( FALSE );
|
|
}
|
|
|
|
const int num_channels = read16LE();
|
|
if( num_channels < 1 || num_channels > 1000 )
|
|
{
|
|
printf( "flpImport::tryImport(): invalid number of channels "
|
|
"(%d)\n", num_channels );
|
|
return( FALSE );
|
|
}
|
|
|
|
const int ppq = read16LE();
|
|
if( ppq < 0 )
|
|
{
|
|
printf( "flpImport::tryImport(): invalid ppq\n" );
|
|
return( FALSE );
|
|
}
|
|
|
|
QProgressDialog pd( trackContainer::tr( "Importing FLP-file..." ),
|
|
trackContainer::tr( "Cancel" ), 0, num_channels );
|
|
pd.setWindowTitle( trackContainer::tr( "Please wait..." ) );
|
|
pd.show();
|
|
|
|
bool valid = FALSE;
|
|
|
|
// search for FLdt chunk
|
|
while( 1 )
|
|
{
|
|
Sint32 id = readID();
|
|
const int len = read32LE();
|
|
if( file().atEnd() )
|
|
{
|
|
printf( "flpImport::tryImport(): unexpected "
|
|
"end of file\n" );
|
|
return( FALSE );
|
|
}
|
|
if( len < 0 || len >= 0x10000000 )
|
|
{
|
|
printf( "flpImport::tryImport(): invalid "
|
|
"chunk length %d\n", len );
|
|
return( FALSE );
|
|
}
|
|
if( id == makeID( 'F', 'L', 'd', 't' ) )
|
|
{
|
|
valid = TRUE;
|
|
break;
|
|
}
|
|
skip( len );
|
|
}
|
|
|
|
if( valid == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
printf( "channels: %d\n", num_channels );
|
|
|
|
instrumentTrack * it = NULL;
|
|
instrument * it_inst = NULL;
|
|
flPlugins cur_plugin = FL_Plugin_Undef;
|
|
|
|
int current_pattern = 0;
|
|
char * text = NULL;
|
|
Uint32 text_len = 0;
|
|
QList<instrumentTrack *> i_tracks;
|
|
int project_cur_pat = 0;
|
|
|
|
int step_pattern = 0;
|
|
int last_step_pos = 0;
|
|
|
|
int env_lfo_target = 0;
|
|
|
|
int ev_cnt = 0;
|
|
|
|
engine::getSongEditor()->clearProject();
|
|
const bool is_journ = engine::getProjectJournal()->isJournalling();
|
|
engine::getProjectJournal()->setJournalling( FALSE );
|
|
|
|
|
|
while( file().atEnd() == FALSE )
|
|
{
|
|
if( ++ev_cnt > 100 )
|
|
{
|
|
ev_cnt = 0;
|
|
qApp->processEvents( QEventLoop::AllEvents, 100 );
|
|
pd.setValue( i_tracks.size() );
|
|
|
|
if( pd.wasCanceled() )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
flpEvents ev = static_cast<flpEvents>( readByte() );
|
|
Uint32 data = readByte();
|
|
|
|
if( ev >= FLP_Word && ev < FLP_Text )
|
|
{
|
|
data = data | ( readByte() << 8 );
|
|
}
|
|
|
|
if( ev >= FLP_Int && ev < FLP_Text )
|
|
{
|
|
data = data | ( readByte() << 16 );
|
|
data = data | ( readByte() << 24 );
|
|
}
|
|
|
|
|
|
if( ev >= FLP_Text )
|
|
{
|
|
text_len = data & 0x7F;
|
|
Uint8 shift = 0;
|
|
while( data & 0x80 )
|
|
{
|
|
data = readByte();
|
|
text_len = text_len | ( ( data & 0x7F ) <<
|
|
( shift += 7 ) );
|
|
}
|
|
|
|
delete[] text;
|
|
text = new char[text_len+1];
|
|
if( readBlock( text, text_len ) <= 0 )
|
|
{
|
|
printf( "could not read string (len: %d)\n",
|
|
text_len );
|
|
}
|
|
|
|
text[text_len] = 0;
|
|
}
|
|
|
|
switch( ev )
|
|
{
|
|
// BYTE EVENTS
|
|
case FLP_Byte:
|
|
printf( "undefined byte %d\n", data );
|
|
break;
|
|
|
|
case FLP_NoteOn:
|
|
printf( "note on: %d\n", data );
|
|
// data = pos how to handle?
|
|
break;
|
|
|
|
case FLP_LoopActive:
|
|
printf( "active loop: %d\n", data );
|
|
break;
|
|
|
|
case FLP_ShowInfo:
|
|
printf( "show info: %d\n", data );
|
|
break;
|
|
|
|
case FLP_Shuffle:
|
|
printf( "shuffle: %d\n", data );
|
|
break;
|
|
|
|
case FLP_MainVol:
|
|
printf( "main-volume: %d\n", data );
|
|
engine::getSongEditor()->setMasterVolume(
|
|
static_cast<volume>( data * 100 /
|
|
128 ) );
|
|
break;
|
|
|
|
case FLP_PatLength:
|
|
printf( "pattern-length: %d\n", data );
|
|
break;
|
|
|
|
case FLP_BlockLength:
|
|
printf( "block length: %d\n", data );
|
|
break;
|
|
|
|
case FLP_LoopType:
|
|
printf( "loop type: %d\n", data );
|
|
break;
|
|
|
|
case FLP_ChanType:
|
|
printf( "channel type: %d\n", data );
|
|
break;
|
|
|
|
case FLP_MixSliceNum:
|
|
printf( "mix slice num: %d\n", data );
|
|
break;
|
|
|
|
|
|
// WORD EVENTS
|
|
case FLP_NewChan:
|
|
printf( "new channel\n" );
|
|
|
|
it = dynamic_cast<instrumentTrack *>(
|
|
track::create( track::INSTRUMENT_TRACK, engine::getBBEditor() ) );
|
|
assert( it != NULL );
|
|
i_tracks.push_back( it );
|
|
it_inst = it->loadInstrument(
|
|
"audiofileprocessor" );
|
|
it->toggledInstrumentTrackButton( FALSE );
|
|
|
|
// reset some values
|
|
step_pattern = 0;
|
|
last_step_pos = 0;
|
|
env_lfo_target = 0;
|
|
|
|
break;
|
|
|
|
case FLP_NewPat:
|
|
current_pattern = data - 1;
|
|
break;
|
|
|
|
case FLP_Tempo:
|
|
printf( "tempo: %d\n", data );
|
|
engine::getSongEditor()->setTempo( data );
|
|
break;
|
|
|
|
case FLP_CurrentPatNum:
|
|
project_cur_pat = data;
|
|
break;
|
|
|
|
case FLP_FX:
|
|
printf( "FX-channel for cur channel: %d\n",
|
|
data );
|
|
break;
|
|
|
|
case FLP_Fade_Stereo:
|
|
printf( "fade stereo: %d\n", data );
|
|
break;
|
|
|
|
case FLP_CutOff:
|
|
printf( "cutoff (sample): %d\n", data );
|
|
break;
|
|
|
|
case FLP_PreAmp:
|
|
printf( "pre-amp (sample): %d\n", data );
|
|
break;
|
|
|
|
case FLP_Decay:
|
|
printf( "decay (sample): %d\n", data );
|
|
break;
|
|
|
|
case FLP_Attack:
|
|
printf( "attack (sample): %d\n", data );
|
|
break;
|
|
|
|
case FLP_MainPitch:
|
|
engine::getSongEditor()->setMasterPitch( data );
|
|
break;
|
|
|
|
case FLP_Resonance:
|
|
printf( "reso (sample): %d\n", data );
|
|
break;
|
|
|
|
case FLP_LoopBar:
|
|
printf( "loop bar: %d\n", data );
|
|
break;
|
|
|
|
case FLP_StDel:
|
|
printf( "stdel (delay?): %d\n", data );
|
|
break;
|
|
|
|
case FLP_FX3:
|
|
printf( "FX 3: %d\n", data );
|
|
break;
|
|
|
|
case FLP_ShiftDelay:
|
|
printf( "shift delay: %d\n", data );
|
|
break;
|
|
|
|
case FLP_Dot:
|
|
{
|
|
printf( "dot/step at: %d\n", data );
|
|
const int pos = data & 0xff;
|
|
if( last_step_pos > pos )
|
|
{
|
|
++step_pattern;
|
|
}
|
|
last_step_pos = pos;
|
|
m_steps.push_back(
|
|
( ( i_tracks.size() - 1 ) << 16 ) |
|
|
( pos + 16 * step_pattern ) );
|
|
break;
|
|
}
|
|
|
|
// DWORD EVENTS
|
|
case FLP_Color:
|
|
printf( "color r:%d g:%d b:%d\n",
|
|
qRed( data ),
|
|
qGreen( data ),
|
|
qBlue( data ) );
|
|
break;
|
|
|
|
case FLP_PlayListItem:
|
|
{
|
|
m_plItems.push_back( data );
|
|
break;
|
|
}
|
|
|
|
case FLP_FXSine:
|
|
printf( "fx sine: %d\n", data );
|
|
break;
|
|
|
|
case FLP_CutCutBy:
|
|
printf( "cut cut by: %d\n", data );
|
|
break;
|
|
|
|
case FLP_MiddleNote:
|
|
data += 8;
|
|
it->setBaseNote( data );
|
|
it->getPianoWidget()->update();
|
|
break;
|
|
|
|
case FLP_DelayReso:
|
|
printf( "delay resonance: %d\n", data );
|
|
break;
|
|
|
|
case FLP_Reverb:
|
|
printf( "reverb (sample): %d\n", data );
|
|
break;
|
|
|
|
case FLP_IntStretch:
|
|
printf( "int stretch (sample): %d\n", data );
|
|
break;
|
|
|
|
// TEXT EVENTS
|
|
case FLP_Text_ChanName:
|
|
if( it == NULL )
|
|
{
|
|
printf( "!! tried to set channel name "
|
|
"but no channel was created so "
|
|
"far\n" );
|
|
break;
|
|
}
|
|
it->setName( text );
|
|
break;
|
|
|
|
case FLP_Text_CommentRTF:
|
|
{
|
|
QByteArray ba( text, text_len );
|
|
QBuffer buf( &ba );
|
|
buf.open( QBuffer::ReadOnly );
|
|
lineno = 0;
|
|
attr_clear_all();
|
|
op = html_init();
|
|
hash_init();
|
|
Word * word = word_read( &buf );
|
|
QString out;
|
|
word_print( word, out );
|
|
word_free( word );
|
|
op_free( op );
|
|
|
|
engine::getProjectNotes()->setText( out );
|
|
outstring = "";
|
|
break;
|
|
}
|
|
|
|
case FLP_Text_Title:
|
|
printf( "project title: %s\n", text );
|
|
break;
|
|
|
|
case FLP_Text_SampleFileName:
|
|
{
|
|
if( it_inst == NULL )
|
|
{
|
|
printf( "!! tried to set sample for "
|
|
"instrument but no channel or "
|
|
"instrument was "
|
|
"created so far\n" );
|
|
break;
|
|
}
|
|
QString dir = text;
|
|
/* if( dir.mid( 1, 11 ) == "Instruments" )
|
|
{
|
|
dir = "\\Patches\\Packs" +
|
|
dir.mid( 12 );
|
|
}*/
|
|
dir.replace( '\\', QDir::separator() );
|
|
if( QFileInfo( configManager::inst()->flDir() +
|
|
"/Data/" ).exists() )
|
|
{
|
|
dir = configManager::inst()->flDir() +
|
|
"/Data/" + dir;
|
|
}
|
|
else
|
|
{
|
|
// FL 3 compat
|
|
dir = configManager::inst()->flDir() +
|
|
"/Samples/" + dir;
|
|
}
|
|
it_inst->setParameter( "samplefile", dir );
|
|
break;
|
|
}
|
|
|
|
case FLP_Version:
|
|
printf( "FL Version: %s\n", text );
|
|
break;
|
|
|
|
case FLP_Text_PluginName:
|
|
{
|
|
instrument * new_inst = NULL;
|
|
if( QString( text ) == "3x Osc" )
|
|
{
|
|
printf( "loading TripleOscillator for "
|
|
"3x Osc\n" );
|
|
new_inst = it->loadInstrument(
|
|
"tripleoscillator" );
|
|
cur_plugin = FL_Plugin_3x_Osc;
|
|
}
|
|
else if( QString( text ) == "Plucked!" )
|
|
{
|
|
printf( "loading Vibed for Plucked!\n"
|
|
);
|
|
new_inst = it->loadInstrument(
|
|
"vibedstrings" );
|
|
cur_plugin = FL_Plugin_Plucked;
|
|
}
|
|
else
|
|
{
|
|
printf( "unsupported plugin: %s!\n",
|
|
text );
|
|
}
|
|
if( new_inst != NULL )
|
|
{
|
|
it_inst = new_inst;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FLP_Delay:
|
|
printf( "delay-data:\n" );
|
|
dump_mem( text, text_len );
|
|
break;
|
|
|
|
case FLP_NewPlugin:
|
|
printf( "new plugin: %s\n", text );
|
|
break;
|
|
|
|
case FLP_PluginParams:
|
|
if( it_inst != NULL &&
|
|
cur_plugin != FL_Plugin_Undef )
|
|
{
|
|
processPluginParams( cur_plugin,
|
|
(const char *) text,
|
|
text_len, it_inst );
|
|
cur_plugin = FL_Plugin_Undef;
|
|
}
|
|
break;
|
|
|
|
case FLP_ChanParams:
|
|
{
|
|
const arpAndChordsTabWidget::arpDirections
|
|
mappedArpDir[] =
|
|
{
|
|
arpAndChordsTabWidget::UP,
|
|
arpAndChordsTabWidget::UP,
|
|
arpAndChordsTabWidget::DOWN,
|
|
arpAndChordsTabWidget::UP_AND_DOWN,
|
|
arpAndChordsTabWidget::UP_AND_DOWN,
|
|
arpAndChordsTabWidget::RANDOM
|
|
} ;
|
|
const Uint32 * p = (const Uint32 *) text;
|
|
arpAndChordsTabWidget * actw = it->m_arpWidget;
|
|
actw->m_arpDirectionBtnGrp->setValue(
|
|
mappedArpDir[p[10]] );
|
|
actw->m_arpRangeKnob->setValue( p[11] );
|
|
actw->m_arpComboBox->setValue( p[12] );
|
|
actw->m_arpTimeKnob->setValue( p[13] / 8.0f );
|
|
//// 100.0f );
|
|
actw->m_arpGateKnob->setValue( p[14] * 100.0f /
|
|
48.0f );
|
|
actw->m_arpGroupBox->setState( p[10] > 0 );
|
|
printf( "channel params: " );
|
|
dump_mem( text, text_len );
|
|
//printf( "channel params: arpdir: %d range: %d time: %d gate: %d\n", p[10], p[11], p[13], p[14] );
|
|
break;
|
|
}
|
|
|
|
case FLP_EnvLfoParams:
|
|
{
|
|
const Uint32 * p = (const Uint32 *) text;
|
|
printf( "envelope and lfo params: " );
|
|
dump_mem( text, text_len );
|
|
envelopeTabWidget * etw = it->m_envWidget;
|
|
envelopeAndLFOWidget * elw = NULL;
|
|
switch( env_lfo_target )
|
|
{
|
|
case 1:
|
|
elw = etw->m_envLFOWidgets[envelopeTabWidget::VOLUME];
|
|
break;
|
|
case 2:
|
|
elw = etw->m_envLFOWidgets[envelopeTabWidget::CUT];
|
|
break;
|
|
case 3:
|
|
elw = etw->m_envLFOWidgets[envelopeTabWidget::RES];
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
++env_lfo_target;
|
|
if( elw == NULL )
|
|
{
|
|
break;
|
|
}
|
|
const float scaling = 0.8f / 65536.0f;
|
|
elw->m_predelayKnob->setValue( p[2] * scaling );
|
|
elw->m_attackKnob->setValue( p[3] * scaling );
|
|
elw->m_holdKnob->setValue( p[4] * scaling );
|
|
elw->m_decayKnob->setValue( p[5] * scaling );
|
|
elw->m_sustainKnob->setValue( p[6] * scaling );
|
|
elw->m_releaseKnob->setValue( p[7] * scaling );
|
|
elw->m_amountKnob->setValue( p[1] ? 1 : 0 );
|
|
elw->updateSampleVars();
|
|
break;
|
|
}
|
|
|
|
case FLP_FilterParams:
|
|
{
|
|
// TODO: Dirty hack!
|
|
// SIMPLE_FLT_CNT equals to old DOUBLE_LOWPASS
|
|
const basicFilters<>::filterTypes
|
|
mappedFilter[] =
|
|
{
|
|
basicFilters<>::LOWPASS,// fast LP
|
|
basicFilters<>::LOWPASS,
|
|
basicFilters<>::BANDPASS_CSG,
|
|
basicFilters<>::HIPASS,
|
|
basicFilters<>::NOTCH,
|
|
basicFilters<>::SIMPLE_FLT_CNT,
|
|
basicFilters<>::LOWPASS,
|
|
basicFilters<>::SIMPLE_FLT_CNT
|
|
} ;
|
|
Uint32 * p = (Uint32 *) text;
|
|
envelopeTabWidget * etw = it->m_envWidget;
|
|
/* printf( "filter values: " );
|
|
for( int i = 0; i < 6; ++i )
|
|
{
|
|
printf( "%d ", ((Sint32*)text)[i] );
|
|
}
|
|
printf( "\n" );*/
|
|
etw->m_filterComboBox->setValue(
|
|
mappedFilter[p[5]] );
|
|
etw->m_filterCutKnob->setValue( p[3] / 255.0f *
|
|
( etw->m_filterCutKnob->maxValue() -
|
|
etw->m_filterCutKnob->minValue() ) +
|
|
etw->m_filterCutKnob->minValue() );
|
|
etw->m_filterResKnob->setValue( p[4] / 1024.0f *
|
|
( etw->m_filterResKnob->maxValue() -
|
|
etw->m_filterResKnob->minValue() ) +
|
|
etw->m_filterResKnob->minValue() );
|
|
etw->m_filterGroupBox->setState( p[3] < 256 );
|
|
break;
|
|
}
|
|
|
|
case FLP_PatternNotes:
|
|
{
|
|
//dump_mem( text, text_len );
|
|
const int bpn = 20;
|
|
Uint32 imax = ( text_len + bpn - 1 ) / bpn;
|
|
for( Uint32 i = 0; i < imax; ++i )
|
|
{
|
|
int ch = *( text + i*bpn + 6 );
|
|
int pos = *( (int *)( text + i*bpn ) );
|
|
int key = *( text + i*bpn + 12 );
|
|
int len = *( (int*)( text + i*bpn +
|
|
8 ) );
|
|
pos /= 6;
|
|
len /= 6;
|
|
note n( len, pos );
|
|
n.setKey( key );
|
|
m_notes.push_back( qMakePair(
|
|
num_channels * current_pattern + ch, n ) );
|
|
|
|
//printf( "note on channel %d at pos %d with key %d and length %d ", (int)*((text+i*bpn+6)), *((int*)(text+i*bpc)), (int) *(text+i*bpc+12), (int) *((int*)(text+i*bpc+8)));
|
|
//printf( "note on channel %d at pos %d with key %d and length %d\n", ch, pos, key, len );
|
|
|
|
//dump_mem( text+i*bpn+4, bpc-4 );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FLP_StepData:
|
|
{
|
|
printf( "step data:\n" );
|
|
dump_mem( text, text_len );
|
|
#if 0
|
|
const int bpn = 20;
|
|
for( int i = 0; i*bpn < text_len; ++i )
|
|
{
|
|
int ch = *( text + i*bpn + 6 );
|
|
int pos = *( (int *)( text + i*bpn ) );
|
|
int key = *( text + i*bpn + 12 );
|
|
int len = *( (int*)( text + i*bpn +
|
|
8 ) );
|
|
pos /= 6;
|
|
len /= 6;
|
|
/*note n( NULL, len, pos );
|
|
n.setKey( key );
|
|
m_notes.push_back( qMakePair(
|
|
num_channels * current_pattern + ch, n ) );*/
|
|
|
|
//printf( "note on channel %d at pos %d with key %d and length %d ", (int)*((text+i*bpn+6)), *((int*)(text+i*bpc)), (int) *(text+i*bpc+12), (int) *((int*)(text+i*bpc+8)));
|
|
//printf( "step-note (?) on channel %d at pos %d with key %d and length %d\n", ch, pos, key, len );
|
|
|
|
dump_mem( text+i*bpn, bpn );
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
default:
|
|
if( ev >= FLP_Text )
|
|
{
|
|
printf( "!! unhandled text (ev: %d, "
|
|
"len: %d):\n",
|
|
ev, text_len );
|
|
dump_mem( text, text_len );
|
|
}
|
|
else
|
|
{
|
|
printf( "!! handling of FLP-event %d "
|
|
"not implemented yet "
|
|
"(data=%d).\n", ev, data );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// process all steps
|
|
for( stepVector::const_iterator it = m_steps.begin();
|
|
it != m_steps.end(); ++it )
|
|
{
|
|
const int ch = ( *it ) >> 16;
|
|
const int pat = ( ( *it ) & 0xffff ) / 16;
|
|
const int pos = ( ( ( *it ) & 0xffff ) % 16 ) * 4;
|
|
while( engine::getBBEditor()->numOfBBs() <= pat )
|
|
{
|
|
track::create( track::BB_TRACK,
|
|
engine::getSongEditor() );
|
|
}
|
|
pattern * p = dynamic_cast<pattern *>(
|
|
i_tracks[ch]->getTCO( pat ) );
|
|
if( p == NULL )
|
|
{
|
|
continue;
|
|
}
|
|
p->addNote( note( -64, pos ), FALSE );
|
|
}
|
|
|
|
// now process all notes
|
|
for( patternNoteVector::const_iterator it = m_notes.begin();
|
|
it != m_notes.end(); ++it )
|
|
{
|
|
const int where = ( *it ).first;
|
|
const int ch = where % num_channels;
|
|
const int pat = where / num_channels;
|
|
if( pat > 100 )
|
|
{
|
|
continue;
|
|
}
|
|
while( engine::getBBEditor()->numOfBBs() <= pat )
|
|
{
|
|
track::create( track::BB_TRACK,
|
|
engine::getSongEditor() );
|
|
qApp->processEvents( QEventLoop::AllEvents, 100 );
|
|
}
|
|
pattern * p = dynamic_cast<pattern *>(
|
|
i_tracks[ch]->getTCO( pat ) );
|
|
if( p != NULL )
|
|
{
|
|
p->addNote( ( *it ).second, FALSE );
|
|
}
|
|
}
|
|
|
|
// process all playlist-items
|
|
for( playListItems::const_iterator it = m_plItems.begin();
|
|
it != m_plItems.end(); ++it )
|
|
{
|
|
int pat_num = ( ( *it ) >> 16 ) - 1;
|
|
if( pat_num > 100 )
|
|
{
|
|
continue;
|
|
}
|
|
while( engine::getBBEditor()->numOfBBs() <= pat_num )
|
|
{
|
|
track::create( track::BB_TRACK,
|
|
engine::getSongEditor() );
|
|
qApp->processEvents( QEventLoop::AllEvents, 100 );
|
|
}
|
|
|
|
bbTrack * bbt = bbTrack::findBBTrack( pat_num );
|
|
trackContentObject * tco = bbt->addTCO( bbt->createTCO( 0 ) );
|
|
tco->movePosition( midiTime( ( ( *it ) & 0xffff ) * 64 ) );
|
|
}
|
|
|
|
if( project_cur_pat < engine::getBBEditor()->numOfBBs() )
|
|
{
|
|
engine::getBBEditor()->setCurrentBB( project_cur_pat );
|
|
}
|
|
|
|
engine::getProjectJournal()->setJournalling( is_journ );
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
|
|
bool flpImport::processPluginParams( const flPlugins _plugin,
|
|
const char * _data,
|
|
const int _data_len, instrument * _i )
|
|
{
|
|
printf( "plugin params for plugin %d (%d bytes): ", _plugin,
|
|
_data_len );
|
|
dump_mem( _data, _data_len );
|
|
switch( _plugin )
|
|
{
|
|
case FL_Plugin_3x_Osc:
|
|
{
|
|
const oscillator::waveShapes mapped_3xOsc_Shapes[] =
|
|
{
|
|
oscillator::SIN_WAVE,
|
|
oscillator::TRIANGLE_WAVE,
|
|
oscillator::SQUARE_WAVE,
|
|
oscillator::SAW_WAVE,
|
|
oscillator::SQUARE_WAVE, // square-sin
|
|
oscillator::WHITE_NOISE_WAVE,
|
|
oscillator::USER_DEF_WAVE
|
|
} ;
|
|
|
|
QDomDocument dd;
|
|
QDomElement de = dd.createElement( _i->nodeName() );
|
|
de.setAttribute( "modalgo1", oscillator::MIX );
|
|
de.setAttribute( "modalgo2", oscillator::MIX );
|
|
for( Uint8 i = 0; i < 3; ++i )
|
|
{
|
|
const Sint32 * d = (const Sint32 *)( _data +
|
|
i * 28 );
|
|
QString is = QString::number( i );
|
|
de.setAttribute( "vol" + is,
|
|
QString::number( d[0] * 100 / 128 ) );
|
|
de.setAttribute( "pan" + is,
|
|
QString::number( d[1] ) );
|
|
de.setAttribute( "coarse" + is,
|
|
QString::number( d[3] ) );
|
|
de.setAttribute( "finel" + is,
|
|
QString::number( d[4] - d[6] / 2 ) );
|
|
de.setAttribute( "finer" + is,
|
|
QString::number( d[4] + d[6] / 2 ) );
|
|
de.setAttribute( "stphdetun" + is,
|
|
QString::number( d[5] ) );
|
|
de.setAttribute( "wavetype" + is,
|
|
QString::number(
|
|
mapped_3xOsc_Shapes[d[2]] ) );
|
|
}
|
|
de.setAttribute( "vol0", QString::number( 100 ) );
|
|
// now apply the prepared plugin-state
|
|
_i->restoreState( de );
|
|
break;
|
|
}
|
|
|
|
case FL_Plugin_Plucked:
|
|
{
|
|
// TODO: setup vibed-instrument
|
|
break;
|
|
}
|
|
|
|
default:
|
|
printf( "handling of plugin params not implemented "
|
|
"for current plugin\n" );
|
|
break;
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
|
|
extern "C"
|
|
{
|
|
|
|
// neccessary for getting instance out of shared lib
|
|
plugin * lmms_plugin_main( void * _data )
|
|
{
|
|
return( new flpImport( static_cast<const char *>( _data ) ) );
|
|
}
|
|
|
|
|
|
// include unrtf-source
|
|
#include "attr.c"
|
|
#include "convert.c"
|
|
#include "error.c"
|
|
#include "hash.c"
|
|
#include "html.c"
|
|
#include "malloc.c"
|
|
#include "output.c"
|
|
#include "parse.c"
|
|
#include "util.c"
|
|
#include "word.c"
|
|
|
|
}
|
|
|
|
|
|
#undef setValue
|