HydrogenImport.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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 instrumentComponentNode = instrumentNode.firstChildElement("instrumentComponent");
  181. if (instrumentComponentNode.isNull())
  182. {
  183. instrumentComponentNode = instrumentNode;
  184. }
  185. QDomNode layerNode = instrumentComponentNode.firstChildElement( "layer" );
  186. while ( ! layerNode.isNull() )
  187. {
  188. if ( nLayer >= MAX_LAYERS )
  189. {
  190. printf("nLayer >= MAX_LAYERS\n");
  191. break;
  192. }
  193. QString sFilename = LocalFileMng::readXmlString( layerNode, "filename", "" );
  194. QString sMode = LocalFileMng::readXmlString( layerNode, "smode", "forward" );
  195. if ( nLayer == 0 )
  196. {
  197. drum_track[sId] = ( InstrumentTrack * ) Track::create( Track::InstrumentTrack,Engine::getBBTrackContainer() );
  198. drum_track[sId]->volumeModel()->setValue( fVolume * 100 );
  199. drum_track[sId]->panningModel()->setValue( ( fPan_R - fPan_L ) * 100 );
  200. ins = drum_track[sId]->loadInstrument( "audiofileprocessor" );
  201. ins->loadFile( sFilename );
  202. }
  203. nLayer++;
  204. layerNode = ( QDomNode ) layerNode.nextSiblingElement( "layer" );
  205. }
  206. }
  207. instrumentNode = (QDomNode) instrumentNode.nextSiblingElement( "instrument" );
  208. }
  209. if ( instrumentList_count == 0 )
  210. {
  211. return false;
  212. }
  213. }
  214. else
  215. {
  216. return false;
  217. }
  218. QDomNode patterns = songNode.firstChildElement( "patternList" );
  219. int pattern_count = 0;
  220. int nbb = Engine::getBBTrackContainer()->numOfBBs();
  221. QDomNode patternNode = patterns.firstChildElement( "pattern" );
  222. int pn = 1;
  223. while ( !patternNode.isNull() )
  224. {
  225. if ( pn > 0 )
  226. {
  227. pattern_count++;
  228. s->addBBTrack();
  229. pn = 0;
  230. }
  231. QString sName; // name
  232. sName = LocalFileMng::readXmlString( patternNode, "name", sName );
  233. QString sCategory = ""; // category
  234. sCategory = LocalFileMng::readXmlString( patternNode, "category", sCategory ,false ,false );
  235. int nSize = -1;
  236. nSize = LocalFileMng::readXmlInt( patternNode, "size", nSize, false, false );
  237. pattern_length[sName] = nSize;
  238. QDomNode pNoteListNode = patternNode.firstChildElement( "noteList" );
  239. if ( ! pNoteListNode.isNull() ) {
  240. QDomNode noteNode = pNoteListNode.firstChildElement( "note" );
  241. while ( ! noteNode.isNull() ) {
  242. int nPosition = LocalFileMng::readXmlInt( noteNode, "position", 0 );
  243. float fVelocity = LocalFileMng::readXmlFloat( noteNode, "velocity", 0.8f );
  244. float fPan_L = LocalFileMng::readXmlFloat( noteNode, "pan_L", 0.5 );
  245. float fPan_R = LocalFileMng::readXmlFloat( noteNode, "pan_R", 0.5 );
  246. QString sKey = LocalFileMng::readXmlString( noteNode, "key", "C0", false, false );
  247. QString nNoteOff = LocalFileMng::readXmlString( noteNode, "note_off", "false", false, false );
  248. QString instrId = LocalFileMng::readXmlString( noteNode, "instrument", 0,false, false );
  249. int i = pattern_count - 1 + nbb;
  250. pattern_id[sName] = pattern_count - 1;
  251. Pattern*p = dynamic_cast<Pattern*>( drum_track[instrId]->getTCO( i ) );
  252. Note n;
  253. n.setPos( nPosition );
  254. if ( (nPosition + 48) <= nSize )
  255. {
  256. n.setLength( 48 );
  257. }
  258. else
  259. {
  260. n.setLength( nSize - nPosition );
  261. }
  262. n.setVolume( fVelocity * 100 );
  263. n.setPanning( ( fPan_R - fPan_L ) * 100 );
  264. n.setKey( NoteKey::stringToNoteKey( sKey ) );
  265. p->addNote( n,false );
  266. pn = pn + 1;
  267. noteNode = ( QDomNode ) noteNode.nextSiblingElement( "note" );
  268. }
  269. }
  270. patternNode = ( QDomNode ) patternNode.nextSiblingElement( "pattern" );
  271. }
  272. // Pattern sequence
  273. QDomNode patternSequenceNode = songNode.firstChildElement( "patternSequence" );
  274. QDomNode groupNode = patternSequenceNode.firstChildElement( "group" );
  275. int pos = 0;
  276. while ( !groupNode.isNull() )
  277. {
  278. int best_length = 0;
  279. QDomNode patternId = groupNode.firstChildElement( "patternID" );
  280. while ( !patternId.isNull() )
  281. {
  282. QString patId = patternId.firstChild().nodeValue();
  283. patternId = ( QDomNode ) patternId.nextSiblingElement( "patternID" );
  284. int i = pattern_id[patId]+song_num_tracks;
  285. Track *t = ( BBTrack * ) s->tracks().at( i );
  286. t->createTCO(pos);
  287. if ( pattern_length[patId] > best_length )
  288. {
  289. best_length = pattern_length[patId];
  290. }
  291. }
  292. pos = pos + best_length;
  293. groupNode = groupNode.nextSiblingElement( "group" );
  294. }
  295. if ( pattern_count == 0 )
  296. {
  297. return false;
  298. }
  299. return true;
  300. }
  301. bool HydrogenImport::tryImport( TrackContainer* tc )
  302. {
  303. if( openFile() == false )
  304. {
  305. return false;
  306. }
  307. return readSong();
  308. }
  309. extern "C"
  310. {
  311. // necessary for getting instance out of shared lib
  312. PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *, void * _data )
  313. {
  314. return new HydrogenImport( QString::fromUtf8(
  315. static_cast<const char *>( _data ) ) );
  316. }
  317. }