Advertisement
Guest User

MIDI to mario paint composer v2.1

a guest
May 1st, 2012
304
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
MatLab 10.78 KB | None | 0 0
  1. %INPUT START
  2. %--------------------------------------------------------------------------
  3.  
  4. %input MIDI file
  5. %the script should work for any MIDI file
  6. infile='C:\Musik\NSF\Uninvited01.mid';
  7. % infile='C:\Musik\Midi\Piano Collection\Final Fantasy 10\03_besaidisland.mid';
  8.  
  9. %path to the Prefs folder of MPC
  10. MPCfold='C:\Spel\mariopaintcomposerpc\Mario Paint Composer PC\Prefs\';
  11.  
  12.  
  13. %file name of the text file containing all the arrays
  14. arrfile='MarioPaintArrList.txt';
  15.  
  16. %you probably don't want to touch the two lines below. you can play around
  17. %with it if you want to, it will change the MPC note each MIDI note is
  18. %assigned to
  19. note1=84; %use 72 or 84 depending on octave. 84 seems correct, though 72 was used before
  20. note2=note1-25;
  21.  
  22. %use bpm='auto' if you want the script to automatically find the bpm
  23. %(bpm = beats per minute), speed of the song
  24. %otherwise you can set this yourself to force a bpm on the song
  25. % bpm='auto';
  26.  
  27.  
  28. %sec_per_beat is the number of seconds between two beats
  29. %suggestion: find the second difference between two beats in the matrix N
  30. %and set sec_per_beat below to this difference
  31. sec_per_beat=0.1167;
  32.  
  33. %beats per minute in the song
  34. bpm=round(60/sec_per_beat);
  35.  
  36. %the sound channel indices you want. set to 'all' if you want to use all
  37. %channels in the MIDI file
  38. wantncs=[1 2 3]; %use [1 2 3] if MIDI is from NSF file, [1 2 3 4 5 6] for SNES
  39.  
  40. % wantncs='all';
  41.  
  42.  
  43. %replace with a number to cut off MIDI after this many seconds
  44. %good for very long MIDI files
  45. %have 'off' if you want to use entire MIDI file
  46. maxsec='off';
  47. % maxsec=30;
  48.  
  49.  
  50.  
  51. %instrument for each sound channel.
  52. %the value on index i is the instrument for channel number i
  53. %using p, star (piano), is usually a safe bet.
  54.  
  55. %example:
  56. %b = mushroom = drum
  57. %p = star = piano
  58. %l = airplane = guitar
  59. %e = flower = trumpet
  60. %f = game boy = blip blop sound
  61. instr={'p','p','b','l','b','f','p','p'};
  62.  
  63. %/INPUT END (you won't need to change anything below here)
  64. %--------------------------------------------------------------------------
  65.  
  66.  
  67.  
  68. %below the script extracts the name of the output file
  69. %the variable songname will be the name of the song
  70. q=find(infile=='\');
  71.  
  72. if numel(q)>0
  73.     songname=infile((q(end)+1):(end-4));
  74. else
  75.     songname=infile(1:(end-4));
  76. end
  77.  
  78.  
  79. %read MIDI file
  80. midi=readmidi(infile);
  81. N = midiInfo(midi,0);
  82. clc;
  83.  
  84. if not(strcmp(maxsec,'off'))
  85.     q=find(N(:,6)>maxsec,1,'first');
  86.     N=N(1:q,:);
  87. end
  88.  
  89. ns=size(N,1);
  90.  
  91. %get all channels
  92. C=unique(N(:,2));
  93.  
  94. if not(strcmp(wantncs,'all'))
  95.     %if wantncs is not 'all';
  96.     C=C(wantncs);
  97.    
  98.     q=false(ns,1);
  99.     for i=1:ns
  100.         if sum(C==N(i,2))>0
  101.             q(i)=true;
  102.         end
  103.     end
  104.     N=N(q,:);
  105. end
  106.  
  107. % error('stop');
  108.  
  109. ns=size(N,1);
  110.  
  111. if strcmp(bpm,'auto')
  112.     %automatic finding of bpm
  113.     %this algorithm seems to give a really high bpm for some songs.
  114.     %it works nice if the song has not arpeggios or anything like that and
  115.     %if the song has a clear beat time.
  116.    
  117.     %you can test this out, but you probably want to manually tweak this
  118.     %if you want your song to sound good
  119.    
  120.     %this algorithm basically computes the shortest time between any two
  121.     %consecutive notes and tests fractions of this as beat time and picks
  122.     %the best option
  123.    
  124.     r=10^6; %round to 4 decimals
  125.    
  126.     t1=N(2:end,5);
  127.     t2=N(1:(end-1),5);
  128.     tdiff=t1-t2;
  129.     tdiff=round(r*tdiff)/r;
  130.     tdiff=tdiff(tdiff>0);
  131.     % error('stop');
  132.     dt=min(tdiff); %beat time in seconds
  133.    
  134.    
  135.    
  136.     disp(['start beat time: ' num2str(60*dt)]);
  137.     k=1;
  138.     eps=10^-2;
  139.     bestval=Inf;
  140.     bestk=0;
  141.     for k=1:64
  142.         %     disp(['Trying k=' num2str(k)]);
  143.         dt0=dt/k;
  144.         u1=tdiff./dt0;
  145.         u2=round(u1);
  146.         u3=abs(u1-u2);
  147.         maxu3=max(u3);
  148.         %     disp(['max u3: ' num2str(maxu3)]);
  149.         if max(u3)<bestval
  150.             bestval=max(u3);
  151.             bestk=k;
  152.         end
  153.         %         break;
  154.         %     else
  155.         %         k=k+1;
  156.         %         if k>20
  157.         %             error('stop');
  158.         %         end
  159.     end
  160.     % disp(['Best k: ' num2str(bestk)]);
  161.     dt=dt./bestk;
  162.     % error('stop');
  163.    
  164.    
  165.     %find beat time...
  166.     % dt=1/k;
  167.     % if dt<10^-3
  168.     %     error('stop');
  169.     % end
  170.    
  171.    
  172.    
  173.     disp(['!!!!       Using k=' num2str(bestk)]);
  174.     disp(['!!!!       beat time in sec: ' num2str(dt)]);
  175.     disp(['!!!!       beat time in frames: ' num2str(60*dt)]);
  176.     disp(['!!!!       bpm: ' num2str(round(60/dt))]);
  177.     %beattime is number of frames between beats
  178.     %higher value = slower beat time
  179.     %this value can be converted to beats per minute by taking
  180.     %3600 and dividing it by beattime.
  181.     % beattime=2;
  182.    
  183.     % sec_per_beat=sec_per_beat;
  184.     %     1 track number
  185.     %     2 channel number
  186.     %     3 note number (midi encoding of pitch)
  187.     %     4 velocity
  188.     %     5 start time (seconds)
  189.     %     6 end time (seconds)
  190.     %     message number of note_on
  191.     %     message number of note_off
  192.    
  193.    
  194.     %clear command window if it's clottered by warning texts...
  195.    
  196.     disp(['Max note: ' num2str(note1)]);
  197.     disp(['Min note: ' num2str(note2)]);
  198.    
  199.     bpm=round(60/dt);
  200.     % bpm=round(60*60/beattime); %always this value for NES games, one per frame
  201.    
  202.  
  203.    
  204.     % bpm=60*tpqn;
  205.     %
  206.     % % bpm=bpm/10;
  207.     %
  208.    
  209.    
  210. else
  211.     dt=60/bpm;
  212. end
  213.  
  214. tvec=N(:,5); %vector with start times for each note
  215. F1=round(tvec/dt)+1; %beat assignment
  216. %fix octaves if necessary...
  217. nc=numel(C);
  218. for i=1:nc
  219.     q=(N(:,2)==C(i));
  220.     t=N(q,3);
  221.    
  222.     %     mindiff=min(t)-note2; %anything lower than 48 is not ok...
  223.     %     maxdiff=max(t)-note1; %anything above 72 is not ok...
  224.     %
  225.     disp(['Channel ' num2str(C(i)) ' has min ' num2str(min(t)) ' and max ' num2str(max(t))]);
  226.    
  227.     newmin=min(t)+12;
  228.     newmax=max(t)+12;
  229.    
  230.     if min(t)<note2 && newmin<=note1 && newmax<=note1
  231.         %         disp(['maxdiff: ' num2str(maxdiff)]);
  232.         %         disp(['mindiff: ' num2str(maxdiff)]);
  233.         disp(['raising channel ' num2str(C(i))]);
  234.         N(q,3)=N(q,3)+12;
  235.     end
  236.    
  237.     newmin=min(t)-12;
  238.     newmax=max(t)-12;
  239.    
  240.     if max(t)>note1 && newmin>=note2 && newmax>=note2
  241.         %         disp(['maxdiff: ' num2str(maxdiff)]);
  242.         %         disp(['mindiff: ' num2str(maxdiff)]);
  243.         disp(['lowering channel ' num2str(C(i))]);
  244.         N(q,3)=N(q,3)-12;
  245.     end
  246. end
  247.  
  248.  
  249. %number of channels
  250. % nc=numel(C);
  251.  
  252. %each row in F is one beat in MPC, each column is an instrument
  253. %the value of F is note number in MIDI terms
  254.  
  255. % F1=round(60*N(:,5)/beattime)+1; %the beat to place this on
  256.  
  257. %dim3: beat number
  258. %dim2: instrument of choise
  259. %dim3: what intrument plays this note
  260. %dim3: note number of choice -> each channel can play more than one note at
  261. %any time. maximum of 5, though
  262. numbeats=max(F1);
  263.  
  264. %F will contain the notes for the MPC file
  265. %each row is one beat
  266. %each column is one potential note on this beat (up to 5 notes on each
  267. %beat)
  268. %the first layer of the third dimension is the note number
  269. %the second layer is what instrument number plays this note
  270. F=NaN(numbeats,5,2);
  271.  
  272. Q=ones(numbeats,1); %what column we are on, on each beat
  273.  
  274.  
  275. %assign
  276. for i=1:ns
  277.     nowch=N(i,2);
  278.     nownote=N(i,3);
  279.    
  280.     q=find(C==nowch);
  281.     if numel(q)>0
  282.        
  283.         nownote=N(i,3);
  284.        
  285.         %find the beat to place this note on
  286.         f1=F1(i);
  287.         if Q(f1)<=5
  288.             F(f1,Q(f1),1)=nownote; %note
  289.             F(f1,Q(f1),2)=q; %instrument
  290.             Q(f1)=Q(f1)+1;
  291.             %             if Q(f1)>5
  292.             %                 disp(['Warning: more than 5 notes on beat ' num2str(i) '. Skipping any further notes on this beat. To solve, try decreasing "beattime".']);
  293.             %             end
  294.         end
  295.     end
  296. end
  297.  
  298. %prepare notes
  299.  
  300. L=cell(note1,1);
  301. L(note1)={'a'}; %C
  302. L(note1-1)={'b'}; %B
  303. L(note1-2)={'c#'}; %A#
  304. L(note1-3)={'c'}; %A
  305. L(note1-4)={'d#'}; %G#
  306. L(note1-5)={'d'}; %G
  307. L(note1-6)={'e#'}; %F#
  308. L(note1-7)={'e'}; %F
  309. L(note1-8)={'f'}; %E
  310.  
  311. L(note1-9)={'g#'}; %D#
  312. L(note1-10)={'g'}; %D
  313.  
  314. L(note1-11)={'h#'}; %C#
  315. L(note1-12)={'h'}; %C
  316.  
  317. L(note1-13)={'i'}; %B
  318.  
  319. L(note1-14)={'j#'}; %A#
  320. L(note1-15)={'j'}; %A
  321.  
  322. L(note1-16)={'k#'}; %G#
  323. L(note1-17)={'k'}; %G
  324.  
  325. L(note1-18)={'l#'}; %F#
  326. L(note1-19)={'l'}; %F
  327.  
  328. L(note1-20)={'m'}; %E
  329.  
  330. L(note1-21)={'n#'}; %D#
  331. L(note1-22)={'n'}; %D
  332.  
  333. L(note1-23)={'o#'}; %C#
  334. L(note1-24)={'o'}; %C
  335.  
  336. L(note1-25)={'p'}; %B
  337.  
  338.  
  339.  
  340. fidarr=fopen([MPCfold songname ']MarioPaint.txt'],'w');
  341.  
  342. %if necessary, add array to ArrList
  343. arrlist=[MPCfold arrfile];
  344. fidnew=fopen(arrlist,'r');
  345. t=fgetl(fidnew);
  346. s0=strfind(t,songname);
  347. fclose(fidnew);
  348. if numel(s0)==0 %check if this song is already in array list
  349.     fid2=fopen(arrlist,'a');
  350.     fprintf(fid2,[songname ']MarioPaint*']);
  351.     fclose(fid2);
  352. end
  353.  
  354. %create array file and first output file
  355. arr_end=']MarioPaint';
  356.  
  357. nowfile_ind=1;
  358. if nowfile_ind<10 %if less than 10, add a 0 character in front
  359.     b='0';
  360. else
  361.     b='';
  362. end
  363. outfile=[MPCfold songname b num2str(nowfile_ind) arr_end '.txt'];
  364. fprintf(fidarr,[songname b num2str(nowfile_ind) '\r']);
  365. fid=fopen(outfile,'w');
  366. beatstr='4/4*';
  367.  
  368. fprintf(fid,beatstr);
  369.  
  370. totcols=0;
  371.  
  372. %dump to MPC file
  373. for i=1:numbeats %for all beats
  374.     k=0; %k counts number of notes played on this beat
  375.     for j=1:5 %for all 5 potential notes on this beat
  376.         v=F(i,j,1); %current note
  377.         w=F(i,j,2); %current instrument
  378.        
  379.         if v<note2 %if too low a note, increase its octave
  380.             v=v+12*ceil((note2-v)/12);
  381.         end
  382.        
  383.         if v>note1 %if too high a note, decrease its octave
  384.             v=v-12*ceil((v-note1)/12);
  385.         end
  386.        
  387.        
  388.         if isfinite(v) %if these is a note on this beat and on this column
  389.             now_note=char(L(v));
  390.             now_instr=char(instr(w));
  391.             fprintf(fid,[now_instr  now_note '+']); %print this note
  392.             k=k+1;
  393.         end
  394.     end
  395.    
  396.     %add additional + at end of beat
  397.     fprintf(fid,[repmat('+',1,6-k) 'q:']);
  398.     totcols=totcols+1;
  399.     if totcols==384
  400.         fprintf(fid,['"%%' num2str(bpm)]);
  401.         fclose(fid);
  402.         nowfile_ind=nowfile_ind+1;
  403.         if nowfile_ind<10
  404.             b='0';
  405.         else
  406.             b='';
  407.         end
  408.         outfile=[MPCfold songname b num2str(nowfile_ind) arr_end '.txt'];
  409.         fprintf(fidarr,[songname b num2str(nowfile_ind)  '\r']);
  410.         disp(['now on file ' outfile]);
  411.         fid=fopen(outfile,'w');
  412.         fprintf(fid,beatstr);
  413.         totcols=0;
  414.     end
  415. end
  416.  
  417. %add : characters so you get 384 of them. this seems necessary for some
  418. %reason
  419. fprintf(fid,repmat(':',1,384-totcols));
  420.  
  421. %print bpm at the end of the file
  422. fprintf(fid,['"%%' num2str(bpm)]);
  423. fclose(fid);
  424. fclose(fidarr);
  425. fclose all;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement