HydrogenImport.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. #include <QDomDocument>
  2. #include <QDir>
  3. #include <QApplication>
  4. #include <QMessageBox>
  5. #include <QProgressDialog>
  6. #include <QTextStream>
  7. #include <stdlib.h>
  8. #include "LocalFileMng.h"
  9. #include "HydrogenImport.h"
  10. #include "Song.h"
  11. #include "Engine.h"
  12. #include "Instrument.h"
  13. #include "InstrumentTrack.h"
  14. #include "Note.h"
  15. #include "Pattern.h"
  16. #include "Track.h"
  17. #include "BBTrack.h"
  18. #include "BBTrackContainer.h"
  19. #include "Instrument.h"
  20. #include "plugin_export.h"
  21. #define MAX_LAYERS 4
  22. extern "C"
  23. {
  24. Plugin::Descriptor PLUGIN_EXPORT hydrogenimport_plugin_descriptor =
  25. {
  26. STRINGIFY( PLUGIN_NAME ),
  27. "Hydrogen Import",
  28. QT_TRANSLATE_NOOP( "pluginBrowser",
  29. "Filter for importing Hydrogen files into LMMS" ),
  30. "frank mather",
  31. 0x0100,
  32. Plugin::ImportFilter,
  33. NULL,
  34. NULL,
  35. NULL
  36. } ;
  37. }
  38. QString filename;
  39. class NoteKey
  40. {
  41. public:
  42. enum Key {
  43. C = 0,
  44. Cs,
  45. D,
  46. Ef,
  47. E,
  48. F,
  49. Fs,
  50. G,
  51. Af,
  52. A,
  53. Bf,
  54. B,
  55. };
  56. static int stringToNoteKey( const QString& str )
  57. {
  58. int m_key = NoteKey::C;
  59. QString sKey = str.left( str.length() - 1 );
  60. QString sOct = str.mid( str.length() - 1, str.length() );
  61. if ( sKey.endsWith( "-" ) )
  62. {
  63. sKey.replace( "-", "" );
  64. sOct.insert( 0, "-" );
  65. }
  66. int nOctave = sOct.toInt();
  67. if ( sKey == "C" )
  68. {
  69. m_key = NoteKey::C;
  70. }
  71. else if ( sKey == "Cs" )
  72. {
  73. m_key = NoteKey::Cs;
  74. }
  75. else if ( sKey == "D" )
  76. {
  77. m_key = NoteKey::D;
  78. }
  79. else if ( sKey == "Ef" )
  80. {
  81. m_key = NoteKey::Ef;
  82. }
  83. else if ( sKey == "E" )
  84. {
  85. m_key = NoteKey::E;
  86. }
  87. else if ( sKey == "F" )
  88. {
  89. m_key = NoteKey::F;
  90. }
  91. else if ( sKey == "Fs" )
  92. {
  93. m_key = NoteKey::Fs;
  94. }
  95. else if ( sKey == "G" )
  96. {
  97. m_key = NoteKey::G;
  98. }
  99. else if ( sKey == "Af" )
  100. {
  101. m_key = NoteKey::Af;
  102. }
  103. else if ( sKey == "A" )
  104. {
  105. m_key = NoteKey::A;
  106. }
  107. else if ( sKey == "Bf" )
  108. {
  109. m_key = NoteKey::Bf;
  110. }
  111. else if ( sKey == "B" ) {
  112. m_key = NoteKey::B;
  113. }
  114. return m_key + (nOctave*12)+57;
  115. }
  116. };
  117. HydrogenImport::HydrogenImport( const QString & _file ) :
  118. ImportFilter( _file, &hydrogenimport_plugin_descriptor )
  119. {
  120. filename = _file;
  121. }
  122. HydrogenImport::~HydrogenImport()
  123. {
  124. }
  125. Instrument * ins;
  126. bool HydrogenImport::readSong()
  127. {
  128. QHash<QString, InstrumentTrack *> drum_track;
  129. QHash<QString, int> pattern_length;
  130. QHash<QString, int> pattern_id;
  131. Song *s = Engine::getSong();
  132. int song_num_tracks = s->tracks().size();
  133. if ( QFile( filename ).exists() == false )
  134. {
  135. printf( "Song file not found \n" );
  136. return false;
  137. }
  138. QDomDocument doc = LocalFileMng::openXmlDocument( filename );
  139. QDomNodeList nodeList = doc.elementsByTagName( "song" );
  140. if( nodeList.isEmpty() )
  141. {
  142. printf( "Error reading song: song node not found\n" );
  143. return false;
  144. }
  145. QDomNode songNode = nodeList.at( 0 );
  146. QString m_sSongVersion = LocalFileMng::readXmlString( songNode , "version", "Unknown version" );
  147. QString sName( LocalFileMng::readXmlString( songNode, "name", "Untitled Song" ) );
  148. QString sAuthor( LocalFileMng::readXmlString( songNode, "author", "Unknown Author" ) );
  149. QString sNotes( LocalFileMng::readXmlString( songNode, "notes", "..." ) );
  150. QString sLicense( LocalFileMng::readXmlString( songNode, "license", "Unknown license" ) );
  151. QString sMode = LocalFileMng::readXmlString( songNode, "mode", "pattern" );
  152. QDomNode instrumentListNode = songNode.firstChildElement( "instrumentList" );
  153. if ( ( ! instrumentListNode.isNull() ) )
  154. {
  155. int instrumentList_count = 0;
  156. QDomNode instrumentNode;
  157. instrumentNode = instrumentListNode.firstChildElement( "instrument" );
  158. while ( ! instrumentNode.isNull() )
  159. {
  160. instrumentList_count++;
  161. QString sId = LocalFileMng::readXmlString( instrumentNode, "id", "" ); // instrument id
  162. QString sDrumkit = LocalFileMng::readXmlString( instrumentNode, "drumkit", "" ); // drumkit
  163. QString sName = LocalFileMng::readXmlString( instrumentNode, "name", "" ); // name
  164. float fVolume = LocalFileMng::readXmlFloat( instrumentNode, "volume", 1.0 ); // volume
  165. float fPan_L = LocalFileMng::readXmlFloat( instrumentNode, "pan_L", 0.5 ); // pan L
  166. float fPan_R = LocalFileMng::readXmlFloat( instrumentNode, "pan_R", 0.5 ); // pan R
  167. if ( sId.isEmpty() ) {
  168. printf( "Empty ID for instrument. skipping \n" );
  169. instrumentNode = (QDomNode) instrumentNode.nextSiblingElement( "instrument" );
  170. continue;
  171. }
  172. QDomNode filenameNode = instrumentNode.firstChildElement( "filename" );
  173. if ( ! filenameNode.isNull() )
  174. {
  175. return false;
  176. }
  177. else
  178. {
  179. unsigned nLayer = 0;
  180. QDomNode layerNode = instrumentNode.firstChildElement( "layer" );
  181. while ( ! layerNode.isNull() )
  182. {
  183. if ( nLayer >= MAX_LAYERS )
  184. {
  185. printf( "nLayer >= MAX_LAYERS" );
  186. continue;
  187. }
  188. QString sFilename = LocalFileMng::readXmlString( layerNode, "filename", "" );
  189. QString sMode = LocalFileMng::readXmlString( layerNode, "smode", "forward" );
  190. if ( nLayer == 0 )
  191. {
  192. drum_track[sId] = ( InstrumentTrack * ) Track::create( Track::InstrumentTrack,Engine::getBBTrackContainer() );
  193. drum_track[sId]->volumeModel()->setValue( fVolume * 100 );
  194. drum_track[sId]->panningModel()->setValue( ( fPan_R - fPan_L ) * 100 );
  195. ins = drum_track[sId]->loadInstrument( "audiofileprocessor" );
  196. ins->loadFile( sFilename );
  197. }
  198. nLayer++;
  199. layerNode = ( QDomNode ) layerNode.nextSiblingElement( "layer" );
  200. }
  201. }
  202. instrumentNode = (QDomNode) instrumentNode.nextSiblingElement( "instrument" );
  203. }
  204. if ( instrumentList_count == 0 )
  205. {
  206. return false;
  207. }
  208. }
  209. else
  210. {
  211. return false;
  212. }
  213. QDomNode patterns = songNode.firstChildElement( "patternList" );
  214. int pattern_count = 0;
  215. int nbb = Engine::getBBTrackContainer()->numOfBBs();
  216. QDomNode patternNode = patterns.firstChildElement( "pattern" );
  217. int pn = 1;
  218. while ( !patternNode.isNull() )
  219. {
  220. if ( pn > 0 )
  221. {
  222. pattern_count++;
  223. s->addBBTrack();
  224. pn = 0;
  225. }
  226. QString sName; // name
  227. sName = LocalFileMng::readXmlString( patternNode, "name", sName );
  228. QString sCategory = ""; // category
  229. sCategory = LocalFileMng::readXmlString( patternNode, "category", sCategory ,false ,false );
  230. int nSize = -1;
  231. nSize = LocalFileMng::readXmlInt( patternNode, "size", nSize, false, false );
  232. pattern_length[sName] = nSize;
  233. QDomNode pNoteListNode = patternNode.firstChildElement( "noteList" );
  234. if ( ! pNoteListNode.isNull() ) {
  235. QDomNode noteNode = pNoteListNode.firstChildElement( "note" );
  236. while ( ! noteNode.isNull() ) {
  237. int nPosition = LocalFileMng::readXmlInt( noteNode, "position", 0 );
  238. float fVelocity = LocalFileMng::readXmlFloat( noteNode, "velocity", 0.8f );
  239. float fPan_L = LocalFileMng::readXmlFloat( noteNode, "pan_L", 0.5 );
  240. float fPan_R = LocalFileMng::readXmlFloat( noteNode, "pan_R", 0.5 );
  241. QString sKey = LocalFileMng::readXmlString( noteNode, "key", "C0", false, false );
  242. QString nNoteOff = LocalFileMng::readXmlString( noteNode, "note_off", "false", false, false );
  243. QString instrId = LocalFileMng::readXmlString( noteNode, "instrument", 0,false, false );
  244. int i = pattern_count - 1 + nbb;
  245. pattern_id[sName] = pattern_count - 1;
  246. Pattern*p = dynamic_cast<Pattern*>( drum_track[instrId]->getTCO( i ) );
  247. Note n;
  248. n.setPos( nPosition );
  249. if ( (nPosition + 48) <= nSize )
  250. {
  251. n.setLength( 48 );
  252. }
  253. else
  254. {
  255. n.setLength( nSize - nPosition );
  256. }
  257. n.setVolume( fVelocity * 100 );
  258. n.setPanning( ( fPan_R - fPan_L ) * 100 );
  259. n.setKey( NoteKey::stringToNoteKey( sKey ) );
  260. p->addNote( n,false );
  261. pn = pn + 1;
  262. noteNode = ( QDomNode ) noteNode.nextSiblingElement( "note" );
  263. }
  264. }
  265. patternNode = ( QDomNode ) patternNode.nextSiblingElement( "pattern" );
  266. }
  267. // Pattern sequence
  268. QDomNode patternSequenceNode = songNode.firstChildElement( "patternSequence" );
  269. QDomNode groupNode = patternSequenceNode.firstChildElement( "group" );
  270. int pos = 0;
  271. while ( !groupNode.isNull() )
  272. {
  273. int best_length = 0;
  274. QDomNode patternId = groupNode.firstChildElement( "patternID" );
  275. while ( !patternId.isNull() )
  276. {
  277. QString patId = patternId.firstChild().nodeValue();
  278. patternId = ( QDomNode ) patternId.nextSiblingElement( "patternID" );
  279. int i = pattern_id[patId]+song_num_tracks;
  280. Track *t = ( BBTrack * ) s->tracks().at( i );
  281. TrackContentObject *tco = t->createTCO( pos );
  282. tco->movePosition( pos );
  283. if ( pattern_length[patId] > best_length )
  284. {
  285. best_length = pattern_length[patId];
  286. }
  287. }
  288. pos = pos + best_length;
  289. groupNode = groupNode.nextSiblingElement( "group" );
  290. }
  291. if ( pattern_count == 0 )
  292. {
  293. return false;
  294. }
  295. return true;
  296. }
  297. bool HydrogenImport::tryImport( TrackContainer* tc )
  298. {
  299. if( openFile() == false )
  300. {
  301. return false;
  302. }
  303. return readSong();
  304. }
  305. extern "C"
  306. {
  307. // necessary for getting instance out of shared lib
  308. PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *, void * _data )
  309. {
  310. return new HydrogenImport( QString::fromUtf8(
  311. static_cast<const char *>( _data ) ) );
  312. }
  313. }