pax_global_header00006660000000000000000000000064147174055020014517gustar00rootroot0000000000000052 comment=2dbffd002a70f8210c2ccae2adc940ecddf56123 midifile-0.4.2/000077500000000000000000000000001471740550200133045ustar00rootroot00000000000000midifile-0.4.2/I_Wanna_Be_Sedated.mid000066400000000000000000001356101471740550200173600ustar00rootroot00000000000000MThdxMTrkBÿXÿYÿQŒtÿ%Sequenced by sargpepp67@earthlink.netÿ/MTrk ®ÿ!ÿDrumsɹ¹ @¹][@ƒc™$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$(((((!$((($*((,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$y$$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$$4$$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(I$4,4$ÿ/MTrkÿ!ÿCymbals/Percussionƒc™4|5;54.r;..o;..;..;..;..;..{;..|;..r;..;..;..;..o;..;..;.4;4.;..u;..|;..;..o;..};..|;..;..;..i;..o;..;..;..;..;.4;4.c;..};..;..;..;..;..o;..;..Y;..o;..Y;..;..;..|;..;.4f;4.;..;..;..;..;..;..;..;..{;..;..c;..;..;..u;..;.4;4.;..;..;..u;..;..;..;..u;..u;..i;..Y;..;..{;..;..;.4|;4.u;..;..;..;..o;..;..c;..;..;..;..;..;..;..;..o;.4;43;33;33l;33;33;33;33o;34;43M;33Y;33x;33|;33V;33o;33o;34|;43i;33{;33;33];33u;33Y;33i;34c;43o;33];33;33i;33x;33x;33i;34;43|;33;33c;33V;33u;33;33;34;43;33;33;33;33;33u;33;34x;43o;33{;33u;33u;33;33;33c;34{;43`;33{;33{;33u;33};33l;33];3..'.E.'..#.M.(..#.[.+.c.'.V.-.o. .f..T..V.".Y"..r....u..V ..Y!..}#..u!....!.. ..`..Q..x. ."..r.. .. ..|..o .4*4L...l..i..|. .}..H.!.!... .o..u ..x ....i..|. ...... .. .`. .i. .Y..|. .. .r....`.."..~....$.4%4S...T.".{ ..=..i.".i.%.].#.`.#.`.".o.#.T.#.V.&.].(.c."4|#4S.V.&.r.#.|.".o.#..#..!4"4.u.(.O.$.o.".c.".|. ..!.O."4}"4.l.#.Q.#.x.".l.".]..o. .l.4{$4.i.&..".}..Q.".Q.".`..i.4"4.].).].#.|.!.Q.!.`. .|.#..4i 4.O.'.Q.$.u.".~.!.l.%.Q."..4!4.].&.u..~.".o. .u.$..%..4c!4.u.)..!.{..u. .Q.".}. ..%6H* 6**H6Q 6 *#'*}66' **T6c6*"*Q6]6* *6c 6*$*l'Y6'*6'x6o*Y6'**6Q6**| 6M 6*#*'~6'6**]6H6*"*Y6@6*6E*l6 * 6*'|'*66T'c*x6'*!6x*~6*6`*x6 *!6'{*6*'6O*c6*6o*x6*6H*6* '*{6'* 6*'x6x6'* *c6[6**}6H6*$'*6'6**H6J6*$6B*~6**u6Q6*"'*{6'*6*'6H6'**o6O6**|6Y6*%*'6'6**|6f6**|6f6**i6J6*"6'V*{'*66x'*`6'*6x*o6*6=* 6 * 6*''6*6E*6*!6o*6 *6Y*|6 *6'*'6*6*o'6 '*6r*o6*6M*6* '*6'*6*l6V6**6Q6**6T6*'*r6'* 6*'x6T'6**6x*6*6=6*!'*u6'*6*6=6* *6Q6**O6B6*#*'6'*6*{'~6u6 '*11'.E.'..#.M.(..#.[.+.c.'.V.-.o. .f..T..V.".Y"..r....u..V ..Y!..}#..u!....!.. ..`..Q..x. ."..r.. .. ..|..o .4*4L...l..i..|. .}..H.!.!... .o..u ..x ....i..|. ...... .. .`. .i. .Y..|. .. .r....`.."..~....$.4%4S...T.".{ ..=..i.".i.%.].#.`.#.`.".o.#.T.#.V.&.].(.c."4|#4S.V.&.r.#.|.".o.#..#..!4"4.u.(.O.$.o.".c.".|. ..!.O."4}"4.l.#.Q.#.x.".l.".]..o. .l.4{$4.i.&..".}..Q.".Q.".`..i.4"4.].).].#.|.!.Q.!.`. .|.#..4i 4.O.'.Q.$.u.".~.!.l.%.Q."..4!4.].&.u..~.".o. .u.$..%..4c!4.u.)..!.{..u. .Q.".}. ..!..'.E.'..#.M.(..#.[.+.c.'.V.-.o. .f..T..V.".Y"..r....u..V ..Y!..}#..u!....!.. ..`..Q..x. ."..r.. .. ..|..o .4*4L...l..i..|. .}..H.!.!... .o..u ..x ....i..|. ...... .. .`. .i. .Y..|. .. .r....`.."..~....$.4%4S...T.".{ ..=..i.".i.%.].#.`.#.`.".o.#.T.#.V.&.].(.c."4|#4S.V.&.r.#.|.".o.#..#..!4"4.u.(.O.$.o.".c.".|. ..!.O."4}"4.l.#.Q.#.x.".l.".]..o. .l.4{$4.i.&..".}..Q.".Q.".`..i.4"4.].).].#.|.!.Q.!.`. .|.#..4i 4.O.'.Q.$.u.".~.!.l.%.Q."..4!4.].&.u..~.".o. .u.$..%..4c!4.u.)..!.{..u. .Q.".}. ..%6H* 6**H6Q 6 *#'*}66' **T6c6*"*Q6]6* *6c 6*$*l'Y6'*6'x6o*Y6'**6Q6**| 6M 6*#*'~6'6**]6H6*"*Y6@6*6E*l6 * 6*'|'*66T'c*x6'*!6x*~6*6`*x6 *!6'{*6*'6O*c6*6o*x6*6H*6* '*{6'* 6*'x6x6'* *c6[6**}6H6*$'*6'6**H6J6*$6B*~6**u6Q6*"'*{6'*6*'6H6'*$6H* 6**H6Q 6 *#'*}66' **T6c6*"*Q6]6* *6c 6*$*l'Y6'*6'x6o*Y6'**6Q6**| 6M 6*#*'~6'6**]6H6*"*Y6@6*6E*l6 * 6*'|'*66T'c*x6'*!6x*~6*6`*x6 *!6'{*6*'6O*c6*6o*x6*6H*6* '*{6'* 6*'x6x6'* *c6[6**}6H6*$'*6'6**H6J6*$6B*~6**u6Q6*"'*{6'*6*'6H6'*$6H* 6**H6Q 6 *#'*}66' **T6c6*"*Q6]6* *6c 6*$*l'Y6'*6'x6o*Y6'**6Q6**| 6M 6*#*'~6'6**]6H6*"*Y6@6*6E*l6 * 6*'|'*66T'c*x6'*!6x*~6*6`*x6 *!6'{*6*'6O*c6*6o*x6*6H*6* '*{6'* 6*'x6x6'* *c6[6**}6H6*$'*6'6**H6J6*$6B*~6**u6Q6*"'*{6'*6*'6H6'*$6H* 6**H6Q 6 *#'*}66' **T6c6*"*Q6]6* *6c 6*$*l'Y6'*6'x6o*Y6'**6Q6**| 6M 6*#*'~6'6**]6H6*"*Y6@6*6E*l6 * 6*'|'*66T'c*x6'*!6x*~6*6`*x6 *!6'{*6*'6O*c6*6o*x6*6H*6* '*{6'* 6*'x6x6'*ÿ/MTrkäÿ!ÿBassÀ"°d° @°][ƒ`r;c;V°@4Q;J;H;T;J;B;B;T;H;J;J;J;B%°@`;f5°@M;Q;`;`;`;Y;H;E;O;T;M;O;];T;°@o;:;°@J;O;H;T;E;@;J;J;E;Y;T;O;J;O.°@ !|'°@!=!T;!!M;!!O;!!J;!!T;!!Y"°@!f °@H;J;J;H;O;M;=;x °@2O°@4Y;O;T;J;O;O;T;O;@;H;E;M;Y;f8°@!o*°@!!O;!!O;!!M;!!T;!!J;!!O;!!V&°@!l°@"M;O;J;Y;T;H;V)°@#Y°@##B;##B;##T;##H;##E;##E;##E-°@#f!°@V;f;O;E;T;r;`,°@#`°@!##T;##O;##Y;##`;##Y;##Q;##f°@&#l°@-`;V;E;Y;B;H;O.°@ #f!°@##M;##Y;##Q;##O;##Y;##O;##M,°@#M°@M;Y;Y;H;T;f;T0°@ !o°@#!!T;!!O;!!J;!!Q;!!H;!!T;!!](°@!#o°@##`;##T;##T;##Y;##Y;##r;##'°@#°@T`"TJM`!E"cQOE#ETr T°@f"°@ O!f$`#l"T[YTE T]TOT ]&°@!|°@!!Y! !c!"!f!"!f!!!Y!$!Y!#!c!!°@°@f"Y Yu Y!i l]T!O!@ TJTV YO ff°@Y°@Y`!u%°@!!°@!!Q!!Y!"!T!$!Y!%!T!#!f!'!T&!°@~0 3°@"{"T [ T!]x °@#r°@##Y#"#O###M#%#H#"#Y#&#`#$#M°@#°@`r] roi" °@#`°@##T# #`# #T#"#f# #Y#!#M##f°@#~°@V ff!f f ~"#°@#`°@##Y##V#%#T#%#O#%#H#%#f##O°@#| °@`f"Mi"Q{"["°@!{°@!#!Y!!!V!!!`! !l!!!Y!!!c!"!f%!°@#|°@##O##Y##Y#"#J##`# #V ##u #°@f°@:TY°@ `°@ `T!x$°@!J°@! !T!!H!"!Y°@!!u °@!!f!!!`!!!H°@!#x°@##E#"#J#"#Y°@ #°@#`##J# #T!##]°@#` °@TO"T$°@Y °@Y"OO  °@u°@B!H'O!°@x°@T M J°@!`°@!!O!"!O!!!H°@!!!M°@! !B!"!E! !O°@!#`°@##E#"#`#"#O#°@ #Y °@##O#"#T#"#T°@ #]°@JY O°@o°@Mc(f °@!°@T`"TJM`!E"cQOE#ETr T°@f"°@ O!f$`#l"T[YTE T]TOT ]&°@#|°@##Y# #c#"#f#"#f#!#Y#$#Y###c!#°@°@f"Y Yu Y!i l]T!O!@ TJTV YO ff°@Y°@Y`!u%°@#!°@##Q##Y#"#T#$#Y#%#T###f#'#T&#°@~0 3°@"{"T [ T!]x °@%r°@%%Y%"%O%#%M%%%H%"%Y%&%`%$%M°@%°@`r] roi" °@%`°@%%T% %`% %T%"%f% %Y%!%M%%f°@%~°@V ff!f f ~"#°@%`°@%%Y%%V%%%T%%%O%%%H%%%f%%O°@%| °@`f"Mi"Q{"["°@#{°@###Y#!#V#!#`# #l#!#Y#!#c#"#f%#°@%|°@%%O%%Y%%Y%"%J%%`% %V %%u %°@°@T`"TJM`!E"cQOE#ETr T°@f"°@ O!f$`#l"T[YTE T]TOT ]&°@#|°@##Y# #c#"#f#"#f#!#Y#$#Y###c!#°@°@f"Y Yu Y!i l]T!O!@ TJTV YO ff°@Y°@Y`!u%°@#!°@##Q##Y#"#T#$#Y#%#T###f#'#T&#°@~0 3°@"{"T [ T!]x °@%r°@%%Y%"%O%#%M%%%H%"%Y%&%`%$%M°@%°@`r] roi" °@%`°@%%T% %`% %T%"%f% %Y%!%M%%f°@%~°@V ff!f f ~"#°@%`°@%%Y%%V%%%T%%%O%%%H%%%f%%O°@%| °@`f"Mi"Q{"["°@#{°@###Y#!#V#!#`# #l#!#Y#!#c#"#f%#°@%|°@%%O%%Y%%Y%"%J%%`% %V %%u %°@O°@H"H"7#OB!B!E'°@#H°@##:#!#@#"#0#%#E##:##@##7°@#%J°@ %%E% %= %%=%%E%%@%%B% %B°@ %T°@ B T @JH T!O°@J°@ @TM$O TO `°@#T°@##@# #=#"#@#"#H#!#B#"#H##H°@#%M°@%%:%%E%%:%%@% %E%%J%%M!°@%E°@ E"E@MO OJ°@f °@@"B EO O O H°@#H°@##B#!#B ##:##$#:#$#@# #@#°@%B°@%%B% %B%%B% %J%%B%%B% %T %°@V°@M@#M#H @!E$BHHT!M O#JO!J#°@#B°@# #@#!#H#"#O#!#O##@#%#@#"#H°@#%Y °@%%J%#%B% %O%!%H%"%B%$%H% %V!% °@ƒEÿ/MTrk,Àÿ!ÿGuitarÁ±j± (±][(ƒc‘3:?::0&?3: ;J@H4@%@;44E;J@M"44E;@ 44H;J@Q44B;@44V;T@O44O;@44M ;Y@T44Y;@44c;O@] 44c@ ; 44c;Y@c44Y;@44c;c@c44B ;@43Y?T:c;:?3@H;H4E+@4;4`;O@Y44@;@4'4c@c;]44O@;4$4T;c@c4@;4B4#4c;c@]4@;4]4#4c;c@Y4;@4H4!4J;c@]4@ 4M;44O;T@T44M;@4"4c@Y;]4;@4T4;Q4c@T"4;@4O4;Y@V4Q#4;@4E4;Q@M4Q#4@;4Y44Y@Y;c 4;@4J44T@Y;Y"4 @;4J$44J;c@T&4@; 4Y!44V;c@`44M;@44J-c9Ta99V±@4‘4 9-4'9J-3-4940-39:4-94M-@9@-494@-:9794- ±@‘4M;`@M4@;±@‘47;:@E4;@4E;=@J4@;4@;3@E@;44H;B@H@4;4B;:@J@;4"4B;J@M@;44B;0@@4@;±@‘4c;`@` 4;@ 4B44T;J@O#4;@4@44c@c;c$4@;4J44M@T;O&4;@4B 44B@`;]%4@;4E"44Y@Y;Y"4@;4B44E;T@]4;@4E#44O;c@Y44@4;@ 4c-c9cR9 -4±@‘479E-E349-94O-M9O49-9E4:-7-49!9@47-79-49E4E-3 -94±@‘@Y;T4`%±@‘447@;44M;T@J±@!‘44B±@‘@;44O;J@H$4@; 4E$4;T@V4Y!44@@; 4±@‘/B;]6Y0±@‘/ ;/:6/ ;H67/B6/;/H/;Y6B/@"/6;/: ;+6/;6 /J;c6O;/6/O;M6E6; / ±@ ‘@`4c;J;4@±@‘;7@H44@; ;B4B@@@;447;:@=@;4;J4=@B@;4;34=@B@;4";E43@H@;4#;H4B@M@4; ±@‘/T;V6E±@‘/;6/O;J63;/6/H;:63;/6 6:/T;:;6/6B;7/7;6/6@;7/@; 6/ ;O6@/O;6/6H;T/B;6/±@‘@M;Q4H@;±@‘4;J@H4H@;4!;=4B@H@;443;:@H@;4 ;E40@H@;4";J4E@J@;4 ;O4@@T@;4!47;J@H;4@±@‘/J6M;O±@‘;/6/=;B63;/6/T;E6:;6/!6:/:;B;6/ ;E67/O;6/;H6@/O;6/;:67/T;6/!;H/Y636;/ ±@‘;O@Y4E@;4±@‘;E47@H@;4;B4=@H@;4 ;=4@@7@;4";J4:@B@4;$;347@E@;4#;J4:@T@;4;B4B@:@;±@‘4 4O9Y-B±@‘94--:9H4=9-4-O9H4=9-4-B9H43-94-J9B4:9-4 9E47-@9-4"4@9@-@9-4!9E43-E94-±@‘;]6H/H±@‘;/660;@/:;/6;=6B/O;/6;B67/O;6/;E6@/T;6/;763/H;6/;E67/J;6/#/B;@6'6/;±@‘;Y@Y4Y 4 ;@;B4@@H@4;'4Q;T@Y&44=;@4;V@Y4Y$440 ;@4"4Y;Y@Y'4@;4@4#4T;Y@Y$4;@4E 4;Y@Y4Y"4@;4B4;Y4Y@T&44J;@4;Y4Y@Y%44O;@4@T;Y4Y&4;@4B"4;T4Y@V(44E;@$4;Y@Y4Y'4@;47%4;Y@Y4Y#4@;4:"4 4Y;Y@Y44J;@%4;Y@Y4O(44B @;!4;Y@Y4O%44B @;"4 @Y;Y4J44Y;@"4-Y9Y4QC±@‘-94-@4H9O%9-4M9O4J-E9-4-B9T43-94 9J-E47-94-B9B409-4±@‘@V4Y;Q4 ±@‘4O@; ±@‘44Y@];Y'443 ;@4#4Y;]@V"4@;4:4!;Y4Y@Q!4;@4:4#4Y;M@T ±@‘4;@474±@ ‘;Q4Y@O&4±@‘;@4B 44Y@M;O±@$‘4; 43@±@‘44T@M;J±@ ‘4@ 4B;±@ ‘44T;Y@J44B;@±@‘4@Y;Y4Y'4±@‘;4J@±@‘4@V;Y4Y'4@;4B%4@V;J4:4@;4Y#49Y4Y-J1±@ ‘49--J9T4B+- 9499Y-H4E-94-B974H-94-:9@4@-94-: 9E439-4 ±@‘@T;`4H44@@; 4"@Y;Y4Y#44J @;4 ;Y4Y@Y 4;4J@44Y;Y@Y 4;@4E4!/O;M6M/±@‘;6/T;76:;/6/E;@63/;6/B;@67/;6/O ;:63/;6/O ;J6+ / ;6/O;B67/;6/H;T6+ 6/;±@‘@T;J4O±@‘;4@;:@J47;@4 4B;O@B;@4;@47@3@;4!;B4@@E;@447;E@H;@4"4@;O@J;4@!;B43@H4;@±@‘;]6J/:;6/±@‘/@;763;/6/B ;O67/;6/B ;B60 /;6/J;H6E/ ;6/B;O6:/;6/Y;H67/;6/Y;E606;±@‘/;f@O4O±@‘@;4;@4=@E@;4";O4B@T;@4 ;E4:@0@;4"4@;B@M;@44E;B@B@;4 ±@‘;T4B@O4;±@‘@;B4:@B4;@±@‘/E;Y6=6; / /#;H67±@ ‘;6//J;O63/;6/H ;:6/;6/J ;M63/;6/: ;@6+/;6/T ;Y6@/;6/`;H676/;±@‘@V;H4Y±@‘;4@;B4@@B@;4!;T4B@M@;4;@4B@E@;4";Y4M@O;@4#;M4E@M@4;$@M;B4:;4@@@;E4+;@±@‘4-O4=9T±@‘-94-B974'-94-H 9@43-94-@ 9@4+-94-O 9B43-94-B974:9-4-J9H479-4!9O47-@49-±@‘;`6H/H±@‘6;/;B/O6:6;/ /O/ /=/%/=/%/7/s±@‘;|4x@V'4 ;@4=4@Y;Q4T(4;@4"44l;u@i'4;@ 4H"4@o4Y;] 4; @4T!44|-O9`'-49-T"--V4B9V)-49-E--E9]4O%-49-E- -H9f4o(-49-:-&/r;i6Y"//T6; /#/u;O6E#//O 6;//f;J6T"//c6;/ /;V6E#/6/Q; / @`;M4V$4;@4#44Y;Q@Y'44:@;44Y;`@i"4@;4H!44]@f;T!4@4:;4;O@E4V44E@;44|;f@`!4@;4H44c@T;` 4;@4E4@c4o;`4;@4Y$4-c49i!-94-T--`9c4Y%--E49 -"-f9u4T!- 49 -E-$-Q9]4` --@94 -"/u;`6O/6;/T/#/r;M6J/6;/`/!/i;x6T /;6/Q/ /u;o6O /6;/B/";f4J@c&443 @;4;f4O@]%4@;474#4u;u@Q%4;4E@#4;|4f@i'44:@;"4;Y@Y4Y 4 @;;B4@@H@4;"@Y4Q;T(4;4= @4;V@Y4Y$4@;404!4Y;Y@Y'4@;4@44T;Y@Y&4@;4E 4;Y@Y4Y"4@;4B4;Y4Y@T&4;@4J4 ;Y4Y@Y%44O@;4BT=Y6Y&6=B6B"6=T6YBV(66EB=%6=YBY6Y'6B=67%6=YBY6Y#6B6:=66Y=YBY!6B=6J(6=YBY6O(6B=6B+6=YBY6O%6B=6B,6BY=Y6J6=B6Y(6/Y;Y6QB±@‘6/; /@6H;O%;6/M;O6J/E/;6!/B;T63;6/ ;J/E676/;!/B;B60;6/±@‘BV6Y=Q 6±@‘=B6O±@ ‘66YB]=Y(663=B66Y=]BV"6B=6:6"=Y6YBQ"6B=6:6#6Y=MBT±@‘6B=676±@‘=Q6YBO&6±@‘B=6B 66YBM=O±@$‘6=B63±@ ‘66TBM=J±@‘6=B6B!±@‘66T=YBJ!6 =B6B!±@‘6BY=Y6Y'6±@‘B=6J"±@‘6BV=Y6Y'6=B6B%6BV=J6:6#B=6Y#6;Y6Y/J4±@‘6/;"/J;T6B,/;6@;Y/H6E/;6/B;76H/;6/:;@6@/;6/:;E63;6/±@‘=`BT6H6B=6@6 BY=Y6Y#6 =B6J6 =Y6YBY!6 =B6J!66Y=YBY 6 =B6E61O=M8M1=±@‘81T=78:=811E=@83=811B=@871=8 1O=:83=181O=J8+8=1"1O=B871=81H=T8+ 8 =1±@‘BT=J6O±@‘6=B=:BJ67B6=%6B=OBBB=6=@67B3B6=$=B6@BEB=6 67=EBHB=6"6@=OBJ=B6!=B63BH6=B±@‘=]8J1:=81±@‘1@=783=811B=O87=181B=B80=18"1J=H8E=811B=O8:18= 1Y=H8781= 1Y=E808=±@‘1=fBO6O±@‘B=6=@6=BEB=6!=O6BBTB=6 =E6:B0B=6#6@=BBMB=6 6E=BBBB=6 ±@‘=T6BBO6=B±@‘=B6:BB6=B±@ ‘1E=Y8=8= 11#=H87±@ ‘=8 11J=O831=81H=:8=81 1J=M831=81:=@8+8=11T=Y8@18= 1`=H878=1±@‘BV=H6Y±@‘6=B=B6@BBB=6"=T6BBMB=6=@6BBEB=6#=Y6MBO=B6"=M6EBMB6=$BM=B6:=6BB@=E6+=B±@‘6/O6=;T;±@‘/6/B;76';6//H;@63;/6/@;@6+;/6/O;B63;6//B;76:;6/"/J;H67;/6";O67/@6;/±@‘=`8H1H18±@‘==B1O8:8=1!1O11=1"1=1$171x±@‘=YBY6Y 6 B==B6@BHB6=#6Q=TBY(6B=6=%6=VBY6Y$6B=606!6Y=YBY'6B=6@66T=YBY&6B=6E 6=YBY6Y"6B=6B6=Y6YBT&6=B6J6 =Y6YBY%6B=6O"6BT=Y6Y&6=B6B"6=T6YBV(66EB=%6=YBY6Y'6B=67%6=YBY6Y#6B=6:"66Y=YBY!6B=6J(6=YBY6O(6B=6B+6=YBY6O%6B=6B,6BY=Y6J6)=B6Y(6/Y;Y6QB±@‘6/; /@6H;O%;6/M;O6J/E/;6!/B;T63;6/ ;J/E676/;!/B;B60;6/±@‘BV6Y=Q 6±@‘=B6O±@ ‘66YB]=Y(6=B6366Y=]BV"6B=6:6"=Y6YBQ"6 B=6:6#6Y=MBT±@‘6B=676±@‘=Q6YBO&6B=±@‘6B 66YBM=O±@$‘6B=63±@ ‘66TBM=J±@‘6=B6B!±@‘66T=YBJ!6B=6B!±@‘6BY=Y6Y'6±@‘B=6J"±@‘6BV=Y6Y'6=B6B%6BV=J6:6#B=6Y#6;Y6Y/J4±@‘6/;"/J;T6B,/;6@;Y/H6E/;6/B;76H/;6/:;@6@/;6/:;E63;6/±@‘BT=`6H6=B6@6 BY=Y6Y#6=B6J6 =Y6YBY!6 B=6J!66Y=YBY 6 B=6E61O=M8M1=±@‘81T=78:=811E=@83=811B=@871=8 1O=:83=181O=J8+8=1"1O=B871=81H=T8+ 8 =1±@‘BT=J6O±@‘6=B=:BJ67B6=%6B=OBBB=6=@67B3B6=$=B6@BEB=6 67=EBHB=6"6@=OBJ=B6!=B63BH6=B±@‘=]8J1:=81±@‘1@=783=811B=O87=181B=B80=18"1J=H8E=811B=O8:18= 1Y=H8781= 1Y=E808=±@‘1=fBO6O±@‘B=6=@6=BEB=6!=O6BBTB=6 =E6:B0B=6#6@=BBMB=6 6E=BBBB=6 ±@‘=T6BBO6=B±@‘=B6:BB6=B±@ ‘1E=Y8=8= 11#=H87±@ ‘=8 11J=O831=81H=:8=81 1J=M831=81:=@8+8=11T=Y8@18= 1`=H878=1±@‘BV=H6Y±@‘6=B=B6@BBB=6"=T6BBMB=6=@6BBEB=6#=Y6MBO=B6"=M6EBMB6=$BM=B6:=6BB@=E6+=B±@‘6/O6=;T;±@‘/6/B;76';6//H;@63;/6/@;@6+;/6/O;B63;6//B;76:;6/"/J;H67;/6";O67/@6;/±@‘=`8H1H18±@‘==B1O8:8=1!1O11=1"1=1$171x±@Z‘6=6BY=Q6T(6=B6"66l=uBi'6=B 6H"6Bo6Y=] 6= B6T!66|/O;`'/6;/T"//V6B;V)/6;/E//E;]6O%/6;/E/ /H;f6o(/6;/:/&1r=i8Y"11T8= 1#1u=O8E#11O 8=11f=J8T"11c8=1 1=V8E#181Q= 1 B`=M6V$6=B6#66Y=QBY'66:B=66Y=`Bi"6B=6H!66]Bf=T!6B6:=6=OBE6V66EB=66|=fB`!6B=6H66cBT=` 6=B6E6Bc6o=`6=B6Y$6/c6;i!/;6/T//`;c6Y%//E6; /"/f;u6T!/ 6; /E/$/Q;]6` //@;6 /"1u=`8O18=1T1#1r=M8J18=1`1!1i=x8T 1=81Q1 1u=o8O 18=1B1"=f6JBc&663 B=6=f6OB]%6B=676#6u=uBQ%6=6EB#6=|6fBi'66:B="66d=dBd66=B=6BY=Q6T(6=B6"66l=uBi'6=B 6H"6Bo6Y=] 6= B6T!66|/O;`'/6;/T"//V6B;V)/6;/E//E;]6O%/6;/E/ /H;f6o(/6;/:/&1r=i8Y"11T8= 1#1u=O8E#11O 8=11f=J8T"11c8=1 1=V8E#181Q= 1 B`=M6V$6=B6#66Y=QBY'66:B=66Y=`Bi"6B=6H!66]Bf=T!6B6:=6=OBE6V66EB=66|=fB`!6B=6H66cBT=` 6=B6E6Bc6o=`6=B6Y$6/c6;i!/;6/T//`;c6Y%//E6; /"/f;u6T!/ 6; /E/$/Q;]6` //@;6 /"1u=`8O18=1T1#1r=M8J18=1`1!1i=x8T 1=81Q1 1u=o8O 18=1B1"=f6JBc 1]*V6$=B‚:1 *ÿ/MTrk9ÿ!ÿGuitar²U² P²[@]@°_’@O ²@’@@O@!@+@%@7@'@:@&@=@#@J@@B@²@’@M²@ ’@@O@$@H@$@=@%@@@%@H@%@H@"@H@²@’@M²@’@@O@#@@@#@J@$@@@#@B@'@H@$@M@²@ ’@J²@ ’@@@@"@B@'@0@*@J@%@0@(@J@'@:²@’@#@O²@’@ @E@!@J@&@0@)@B@)@:@)@@@'@B²@’@"@H²@’@"@@@'@@@%@:@'@H@#@:@!@@@#@J²@’@#@H²@’@ @B@%@B@&@@@&@E@$@J@'@=@%@E²@ ’@#@H ²@ ’@"@:@$@B@#@H@(@=@&@B@!@:@ @B+²@’@¥L²@’@M"@@:@$@:@&@@@(@@@&@3@$@M@ @M@²@#’@O ²@’@ @B@%@E@(@@@'@@@(@H@(@7@'@B@ ²@’@J²@’@"@:@&@@@&@H@&@H@%@:@&@B@"@J²@’@%@J²@’@#@@@(@E@'@B@%@@@&@=@$@J@(@B²@’@#@M²@ ’@"@:@%@B@%@@@(@J@&@B@(@H@#@J ²@ ’@"@O ²@’@#@H@)@E@&@7@(@H@#@3@&@7@'@H²@’@#@H²@’@'@7@,@H@%@7@&@:@%@B@#@E@ @J²@’@!@J²@ ’@!@:@"@7@$@3@#@=@ @H@%@E@!@O@²@"’@lu@@u@@lu@@u@@u@@u@@u@@u@@u@@u@@u@@ru@@u@@u@@u@@u@@u@@~u@@fu@@u@@xu@@u@@fu@@u@@xu@@u@@{u@@xu@@xu@@u@@u@@u@¥BluBBuBBluBBuBBuBBuBBuBBuBBuBBuBBuBBruBBuBBuBBuBBuBBuBB~uBBfuBBuBBxuBBuBBfuBBuBBxuBBuBB{uBBxuB BT‚}Bÿ/MTrk1ÿ!ÿGuitarój³ P³][(ƒ]“'T3E.B<.(T/04@3'$/(4(Y4M/:³@“/(4 (J4E/0#/(4³@“(O4O/B&(/4(Y4B/@³@“(/4(@4O/3%/4((B/74T ³@“/(4(@/74B%4/((:/E4M³@"“4(/(J/+4@&/4( ³@“(Y4J/:%(/4(`4B/3³@“(/4(Q4f/B$(/4(T/:4O"/(4(T/@4f³@ “/(4'T3Y.T&.3' (B/34B /(4(O4`/J'/³@“(4(Y4T/@&/(4(J/34B³@“/4((O/@4Y&/(4(E/@4f(/4(³@“(Y/=4`&4/((B/34E'4/³@“( (T/=4B%(4/(@4T/7&(/4 ³@ “(T/E4O&4(/(B/:4M&/4(/=(T4`³@ “/4(4Y/=(]&(4/(M4J/: ³@“(4/(B4T/3$(/4³@“(Y4Y/:%4/(/34O(H³@ “4(/(@4T/3%4(/(M4J/3&4/(³@“(E47/7&4/(4:/7(B$4/(³@“/@4H(B"4/((:/+4E&(4/(T/:4V³@ “4(/4Y/J(B%/4((J4Y/J³@“4/((@4:/:%4/(/=4O(B³@ “4/(4`/:(V'(/4(B4E/@#/4(4x-o³@=“-4!4J-@(-4Q4T-B4-4E-E-4-34T4--H4T4-³@“(@4H/@$/(4(H4@/:!³@“4(/(B4T/3%(4/(H/:4E³@$“4(/(V4T/E&4/( ³@“(H/@4V%(/4(J/74O&(4/³@“4B/E(B&/(4/H(Y4O&4/(4H/:(T³@“/(4(E4H/3&4(//:4B(O³@$“(4//B(T4M'4(/³@“4E/=(O&(4/(B4H/7&4/(/@4T(H³@#“/(44@/:(H&/(44B(M/@³@#“/4((@/74=&/4(4O/T(E³@#“4(//@(T4H&(4/³@“(J/E4V&/4((J/M4O&4(/(O/@47³@ “/4(4]-T@³@“-4%4T-J,-4C4H-B&-44O-:&-44M-H'4-4B-H³@“-44J/H'/4(`4`/T³@ “/(4(Y4T/E'4(/(T³@“/=4T&(4/(T/H4H'(4/4Y(O/@³@'“/(4(T4H/@(/4(4H/7(J³@ “/4(/:6}$³@“6//=6T'6/6B/='/66:/@'/66J/O&/66J/@&6//T6o'6/6O/7 ³@“6//B(V4V³@“/(4(]/:4B'4(/(V/:4H&4(/(O/:4=&/4((o/:4T&4(/(Y4B/:&4/((Q4M/7&/(4(`4H/3³@ “4/(6M/H³@“/66O/:&/66M/7&/6/76E&66M/@!//6/76H&6//J6f'6/6J/:³@ “/64Y/3(J³@ “(/4(O/74@$(/4(O/:4@%(/4(Y/74M$4/(/E(O4=%/(4(T4B/H&/(4(B4O/@%(4/(`4J/:³@“/(46M/J&/6³@“6H/3&/6/E6T&6//B6J&6//H6O&6//76O&6//E6o&6/6E/:&6/³@“(H/H&/(³@“(M/3%(/(`/J%(/(`/@³@“/((J/H%(/³@“(O/J$(/(J/@$(/(M/:³@“(/4J-J&4-4:-: ³@“-4-74O(4-³@“4H-B&-44B-E³@ “4-4T-E$4-4M-H%4-4H-E³@“4-6T/E'/66J/O³@“6//:6B'6/6O/J³@“/6/O6T'6/6O/E³@&“/6/O6H'6/6J/T ³@“/6/E4T(J'(4/(O/:4H'4/( ³@ “(O/:4@%(4/ ³@“(M/04=&(4/(:/=4@$(4/³@“(H/B4O%(/4(J/B4H$(4/³@ “(B/B4B$(4/(T/=4Y%(/4(H/H4T ³@“(4/(O/@4M%(/4(`4T/:³@“(/4/B4c8/4(c(³@“(H'(4/'(B'(/³@“4(M4Q/B&4/(/E(J4: ³@“4/((B/=4@&(4/4H/J(O³@#“(/4(H4J/J'/4(³@“(J/B4J'4/((7/E4M'4/(³@“/@4H(M'(4//@4M(V'(4/ ³@ “/@(J4M'4(/(O/O4E'4/(³@“/@4T(J'(4//H(T4T'4(/³@“(E/@4M'4/((B/E4B'4/((:/:4M ³@“4/(4O-YL-4³@“-H4Y24-B4J-7'-44E-:'-44Y-J'-44E-J&³@“-4(O4T/J'/(4(=4Q/@³@$“(/4(M/H4O/4³@“(/74O(J/4(/E4H(B%/(4(:/E4T³@“/(4(T/J4O"4(/('/:4J ³@“(4/(H/E4T$4(/(H4T/J³@&“/4((T4T/O$4/((M/O4] ³@“4/((O4`/B&(/4(E/H4O³@“4(/(B/O4V%(4/(H/M4Y³@“(4//M(J4B'4(/(Y/T4J³@“4/((O/H4T'4/(/M(Y4H³@“4(//J4J(J'(4/(Y/T4M³@$“4/((O/J4M'4/((@/M4T³@“(4/4T-TF³@“4-4T-E%-4K4T-='-4-=4H%-4-@4O'4--:4H#³@“4-(E/O4O&/(4(O/:4E ³@“(4/(Y4Y/B#(/4(:/:4H³@“(4/(:/E4Y&(4/ ³@ “(O/Y4Y%(4/(O4B/B'/4((@/J4M³@“(4/6c/O'/³@“66E/:%6/6M/E'/66E/:'/66J/B'/6/:6O'6/6J/@'/6/E6J%³@“6/(O/T4Y&(4/³@“(J/74O'4/((T/34H'4/((T4M/H'/4((J4B/:'/4((O/:4J'4/(4@/:(B'(/44H/:(@'(/4³@“/O6V'6//H6H ³@“6//B6T'6//:6J'6//J6H'6//B6O'6//E6B'6//H6H!³@“6/(O/H4`%(4/ ³@“(H/@4H%(4/(O/@4B&(4/(:4O/:'/4((B/B4O'4/((H/:4='4/((J4B/E'/4((B4O/B"³@“/4(6f/T'/6/B6H³@$“6/6B/:)/66=/7)/6/@6B&/6/:6J&/66H/H&6/6J/7&6/ ³@ “/E(B4H&4/((Y/:4T³@“/4((Q/@4T%4(/(O4E/7&/(4(E/:4@&/4((O/@4J%/4(/E(H4B&4(/(B/=4E#³@“/4(4J-Y-4³@“-H4B4-#-Y4T-4-M4B4-#-H4E-44@-:-44M-B-44@-:-4³@“6f/O³@“/6/06B6/!/O6B6/ /@6E/66Y/O/66H/E/66T/M/6 6J/J/6³@“(`/J³@“(//E(T(/(Y/J(/(J/:(/(O/B(/(O/B(/(T/B(/(H/E /(³@“4V-]³@“4 --J4H-44J-E4-4O-@4-4@-@4-4O-B-4%4O-H-4!-=4J³@“4-6o/f³@ “/6/J6Y6/ /J6H6//B6E6/ /H6:/6/@6@/6!/B6J6/ 6M/J6/³@“/Y(l³@ “/((T/@/( (=/M(/"/E(@/(%/B(@(/!/@(B(/#/:(@/($/H(O/(³@ “/`(Q/(³@“/O(O/((Y/f/( /M(T(/!/T(Y/(/B(T/(/@(M/(/J(O/(³@“4]-o³@ “4-4E-J4-4O-B4-4J-E-4 -J4M4-4T-@-4!4f-J-44M-@³@“4-6`/]³@“/ 6/O6T/6/T6T6/!6O/H6/!/O6T/6$6c/Y/6#/O6O6/6f/Y/6³@“/T(O³@ “/((T/B/((O/T(/(J/@(/(T/Y(/(Y/B(/(f/T/((J/J(/³@[“(O/:4H'4/( ³@ “(O/:4@%(4/ ³@“(M/04=&(4/(:/=4@$(4/³@“(H/B4O%(/4(J/B4H$(4/³@ “(B/B4B$(4/(T/=4Y%(/4(H/H4T ³@“(4/(O/@4M%(/4(`4T/:³@“(/4/B4c8/4(c(³@“(H'(4/'(B'(/³@“4*M6Q1B&61*1E*J6: ³@“61**B1=6@&*616H1J*O³@#“*16*H6J1J'16*³@“*J1B6J'61**71E6M'61*³@“1@6H*M'*611@6M*V'*61 ³@ “1@*J6M'6*1*O1O6E'61*³@“1@6T*J'*611H*T6T'6*1³@“*E1@6M'61**B1E6B'61**:1:6M ³@“61*6O/YL/6³@“/H6Y26/B6J/7'/66E/:'/66Y/J'/66E/J&³@“/6*O6T1J'1*6*=6Q1@³@$“*16*M1H6O16³@“*176O*J16*1E6H*B%1*6*:1E6T³@“1*6*T1J6O"6*1*'1:6J ³@“*61*H1E6T$6*1*H6T1J³@&“16**T6T1O$61**M1O6] ³@“61**O6`1B&*16*E1H6O³@“6*1*B1O6V%*61*H1M6Y³@“*611M*J6B'6*1*Y1T6J³@“61**O1H6T'61*1M*Y6H³@“6*11J6J*J'*61*Y1T6M³@$“61**O1J6M'61**@1M6T³@“*616T/TF³@“6/6T/E%/6K6T/='/6/=6H%/6/@6O'6//:6H#³@“6/*E1O6O&1*6*O1:6E ³@“*61*Y6Y1B#*16*:1:6H³@“*61*:1E6Y&*61 ³@ “*O1Y6Y%*61*O6B1B'16**@1J6M³@“*618c1O'1³@“88E1:%818M1E'188E1:'188J1B'181:8O'818J1@'181E8J%³@“81*O1T6Y&*61³@“*J176O'61**T136H'61**T6M1H'16**J6B1:'16**O1:6J'61*6@1:*B'*166H1:*@'*16³@“1O8V'811H8H ³@“811B8T'811:8J'811J8H'811B8O'811E8B'811H8H!³@“81*O1H6`%*61 ³@“*H1@6H%*61*O1@6B&*61*:6O1:'16**B1B6O'61**H1:6='61**J6B1E'16**B6O1B"³@“16*8f1T'181B8H³@$“818B1:)188=17)181@8B&181:8J&188H1H&818J17&81 ³@ “1E*B6H&61**Y1:6T³@“16**Q1@6T%6*1*O6E17&1*6*E1:6@&16**O1@6J%16*1E*H6B&6*1*B1=6E#³@“16*6J/Y/6³@“/H6B6/#/Y6T/6/M6B6/#/H6E/66@/:/66M/B/66@/:/6³@“8f1O³@“18108B81!1O8B81 1@8E188Y1O188H1E188T1M18 8J1J18³@“*` **O1:6H'61* ³@ “*O1:6@%*61 ³@“*M106=&*61*:1=6@$*61³@“*H1B6O%*16*J1B6H$*61³@ “*B1B6B$*61*T1=6Y%*16*H1H6T ³@“*61*O1@6M%*16*`6T1:³@“*161B6c816*c*³@“*H'*61'*B'*1³@“6*M6Q1B&61*1E*J6: ³@“61**B1=6@&*616H1J*O³@#“*16*H6J1J'16*³@“*J1B6J'61**71E6M'61*³@“1@6H*M'*611@6M*V'*61 ³@ “1@*J6M'6*1*O1O6E'61*³@“1@6T*J'*611H*T6T'6*1³@“*E1@6M'61**B1E6B'61**:1:6M ³@“61*6O/YL/6³@“/H6Y26/B6J/7'/66E/:'/66Y/J'/66E/J&³@“/6*O6T1J'1*6*=6Q1@³@$“*16*M1H6O16³@“*176O*J16*1E6H*B%1*6*:1E6T³@“1*6*T1J6O"6*1*'1:6J ³@“*61*H1E6T$6*1*H6T1J³@&“16**T6T1O$61**M1O6] ³@“61**O6`1B&*16*E1H6O³@“6*1*B1O6V%*61*H1M6Y³@“*611M*J6B'6*1*Y1T6J³@“61**O1H6T'61*1M*Y6H³@“6*11J6J*J'*61*Y1T6M³@$“61**O1J6M'61**@1M6T³@“*616T/TF³@“6/6T/E%/6K6T/='/6/=6H%/6/@6O'6//:6H#³@“6/*E1O6O&1*6*O1:6E ³@“*61*Y6Y1B#*16*:1:6H³@“*61*:1E6Y&*61 ³@ “*O1Y6Y%*61*O6B1B'16**@1J6M³@“*618c1O'1³@“88E1:%818M1E'188E1:'188J1B'181:8O'818J1@'181E8J%³@“81*O1T6Y&*61³@“*J176O'61**T136H'61**T6M1H'16**J6B1:'16**O1:6J'61*6@1:*B'*166H1:*@'*16³@“1O8V'811H8H ³@“811B8T'811:8J'811J8H'811B8O'811E8B'811H8H!³@“81*O1H6`%*61 ³@“*H1@6H%*61*O1@6B&*61*:6O1:'16**B1B6O'61**H1:6='61**J6B1E'16**B6O1B"³@“16*8f1T'181B8H³@$“818B1:)188=17)181@8B&181:8J&188H1H&818J17&81 ³@ “1E*B6H&61**Y1:6T³@“16**Q1@6T%6*1*O6E17&1*6*E1:6@&16**O1@6J%16*1E*H6B&6*1*B1=6E#³@“16*6J/Y/6³@“/H6B6/#/Y6T/6/M6B6/#/H6E/66@/:/66M/B/66@/:/6³@“8f1O³@“18108B81!1O8B81 1@8E188Y1O188H1E188T1M18 8J1J18³@“*`1J³@“*11E*T*1*Y1J*1*J1:*1*O1B*1*O1B*1*T1B*1*H1E 1*³@“6V/]³@“6 //J6H/66J/E6/6O/@6/6@/@6/6O/B/6%6O/H/6!/=6J³@“6/8o1f³@ “181J8Y81 1J8H811B8E81 1H8:181@8@18!1B8J81 8M1J81³@“1Y*l³@ “1**T1@1* *=1M*1"1E*@1*%1B*@*1!1@*B*1#1:*@1*$1H*O1*³@ “1`*Q1*³@“1O*O1**Y1f1* 1M*T*1!1T*Y1*1B*T1*1@*M1*1J*O1*³@“6]/o³@ “6/6E/J6/6O/B6/6J/E/6 /J6M6/6T/@/6!6f/J/66M/@³@“6/8`1]³@“1 81O8T181T8T81!8O1H81!1O8T18$8c1Y18#1O8O818f1Y18³@“1T*O³@ “1**T1B1**O1T*1*J1@*1*T1Y*1*Y1B*1*f1T1**J1J*1³@"“1J³@!“11E*T*1*Y1J*1*J1:*1*O1B*1*O1B*1*T1B*1*H1E 1*³@“6V/]³@“6 //J6H/66J/E6/6O/@6/6@/@6/6O/B/6%6O/H/6!/=6J³@“6/8o1f³@ “181J8Y81 1J8H811B8E81 1H8:181@8@18!1B8J81 8M1J81³@“1Y*l³@ “1**T1@1* *=1M*1"1E*@1*%1B*@*1!1@*B*1#1:*@1*$1H*O1*³@ “1`*Q1*³@“1O*O1**Y1f1* 1M*T*1!1T*Y1*1B*T1*1@*M1*1J*O1*³@“6]/o³@ “6/6E/J6/6O/B6/6J/E/6 /J6M6/6T/@/6!6f/J/66M/@³@“6/8`1]³@“1 81O8T181T8T81!8O1H81!1O8T18$8c1Y18#1O8O818f1Y18³@“1T*OBT=O6J1*ƒ,B=6ÿ/MTrk Lÿ!ÿVoiceÄ´´ @´][(’"”GZGGGG| GGGGp GGGG GG| GG|"GG2G ID2GRG&G|GG|GGGGG GG"GGGBG6GGGGGG G9GIc;IGG1GG GG"GpG$GG#GG"GG#GSG%GG"GG"G|G$G&GI&IGmG1GG!G|GGpG"GG$GG%GG!GOG*GG!GpG&GG%GG I"IGsG@`@EVE"DaD@l@ I^IGƒRG‡G\GGG!G|G GG!GG!G|G#GG"GG%GG GGI)IGkG E;EDmwD=E!EDZDBiB@,@BRB&DADcDDDD$DD%D|MD+DKD-DaDB)BDm.DE.EDGGGG!GG$GpG#GG%GG%GSG%GG%G|G"GyG$G$GIc!IGyG;GG!G|G"GG#GpG!GG"GG!GmJG.GG$GG$GG#G1G I4IGlG @Q@'EsEDcD@cyI@MIGƒG¥eITI#IIIIII"II"IKAKI$II"II!IIIIK:KInI GD4äDHLQV[`ejptx|B´    !#%”D´&()+,-/01345789:<ä@ÿ/MTrk ùÿ!ÿPiano ŵdµ (µ][(ƒa•dOXHµ@•XdXOdMdXXMdOXd#XEdHdX"XJd@dX XEdBdX$XBdBd XXEdBdX$XJdHdX XHdBdX XHd@dX!XEd:dXXMdBdX dEXBXd$XJdJdX X=d@dX$XMdBdX XEd=dX%XMdBdX X@d:dX XJdJdXX=d7dX#XMdYdXd:X7Xd#XHdHXd!XEd@dX#XJdHdX"X@d=dX#XHdBXd!XJdBdXXJdJdXXHdTXµ@•dždTX`Xdµ@ •XOdMdXXOdJdX XHdBdX!dOXJXdXJdBdX!XVd`dXXTdJdX XTdOdX dOXOXd"dOXOXdXOdMdX#XHdMdX!XTdJdX$dMXMXd!XTdYdX"dYXVXd"dOXOXd#X]d`dX!XHdJdX"dTXOXd XHdOdX"dYXYXd!dJXHXd!dOXYXdXOdOXd#XTdOXd#dJXMXdXOdcXd dOXJXd$d]X]Xd$XTdMXd$XYdOXd"XJdOXd"dYX`Xd"XOdTdX"dTXM!XddMXMXd#XidQXddTXTXd"XYd]dXXTdTdX$XTdMdXXOdOXd!dMXTXd#dOXVXd"XTdQXddOXHXd dYXTXd dOXHXd#X`dOdX"XHdOXd"XTdO"XddMXTXd$XQdYXd dJXOXd"dYXQXdXOdTXd"dMXYXd dTXTXddYXYXddQXQXddYXTXdX]duµ@•Xd¥Pµ@•dYXYXdXOdOdX"XTdTdX#XOdMdX"XJdMdX$X:dHdX%XOdQXd!XTdHdX#XQdYdX XEdOXd#dYXfXdXOdQdX#XJdTXd XMdMXd$d]XfXdXHdJdX X]d`XdXOdOXd dYXoXd XTdfXd d`XTXddHXOXd"XTdMdX dOX@Xd dOXMXd!d`XTXd!XOd`XddJXOXd!dOX`Xd!dOXTXd"d`XYXd XMdMXd#dYXYXdXTdMdX!XYdOdX XJdMXdX]dTXd!XOdMdX#X`dfXdXHdMXddTXYXddOXJXd!XYdodXXOdHdXXTdOdX XJd`Xd"XOdVXdXOdOdX!dOXTXd!XHdMdX%dOXHXd!dTXOXd"dQXMXd#dTXTXd$X]dVXd"XOdTdX#dTXVXd#dTXTXd!XTdYXd#XTdVdX!dOXVXdX`dMdX XYdY dXX]du Xd´µ@ •foZ`Zf#ZVfVZfZxf|ZfZOfTZf!foZuZfZOffZf%Z|f]Zf ZYfuZf$fZ]Zf fQZTZf#Z]fYZf Z]fQfZ#Z|f~ZfZ`fMZf'ZffZ Z~f|Zf!Z|f~Zf#Z|fZf"Z~fYfZ!ZffVfZ%ZcffZ!Z]foZf%ZcfQfZZYfMZf%Zuf]Zf"ZlfVZf%Z]fQZfZof]ZfZTfuZf!ZYf`Zf&Z~fxZfZ]fTZf#ZlfQZf$Z|frZf%ZfoZf#Zcf|Zf Z`f~ZfZofxZf%ZfZfZ`fTZf#ZVflZfZQf]Zf Zff[ZfZYfYZfZofuZfZofofZ!ZufZfZOfQZf"ZYf`ZfZ`foZf!foZ]Zf ZffoZf"Zff`ZfZof`Zf%Z`flZf!ZTfoZf!ZcfVZf"Zof|Zf$ZTfiZfZOfJZf$Z]f~fZ!Z`foZf$ZTf`Zf"ZofOZf"Z`fVfZ#Z]fofZ#ZYflZf ZYffZf$ZYfxZf!ZifoZf$ZffuZf#ZcfZf#ZofZf$Z`ffZf&Z`fcZf!Z]f{Zf%Zuf|fZ%ZYfcZf$f[ZTZf#fYZiZf Z`fTZf!ffZ]Zf$Z]fTfZ$ZlfoZff|ZTZf#ZQfTfZ'Z]frZf%foZ]Zf"Z|foZf@µ@ÿ/MTrkÎÿ!ÿGuitarƶU¶ ¶][(‚·!–*O1T1*!*f1@1**`1T*1*O1B1**c1E1**`1T1* 1H*`*11@*~1*6Q/O/6!6H/:/6 /H6O 6/6f/@6/ 6T/E6/6M/H/66O/=/6 6O/T/6!8i1J1 88Y1H18"1B8Y811O8Y81$1O8`81 8M1E18"8T1O18$1J8Y81*Q1f*1*Y1@1* *V1`1*1Y*Q1*1M*Y1**T1Y1*"*`1`1* *T1Y1**o1`1* *T1V1*"1`*Y1**T1J1* *Q1Y1*1`*f1*1T*Q1*1]*Q1*6Y/O/66T/B/6$6u/O6/6`/T6//Y6Q6/6O/T/66~/Q/6 6x/Y/681f188V1T18$8l1V18!1O8c81"1J8{81#8o1f81#8c1O188f1E81*x1o*1*`1]1*!*Y1Y*1!*Y1E1*#*Y1f*1 *O1]*1"*u1l1**T1O/:/ 1*!*Y1l*1*H1]*1"*u1o1**T1V1*1Y*Y*1*o1Y1*!1Y*Y*1 *T1T*16T/V6/ 6Y/H/6!6l/O/66O/E/6%/M6f6/"6Y/E/6&6|/J/6!6o/Y/6$1Y8c18#8u1B18&1Y8|81!1H8f81&8f1J18"8T1B18'8u1B18 1Y8M81*O1V*1*Y1T*1 *O1V*1*T1B*1!1|*Y*1*J1Y1*"*f1M*1*B1T*1!*V1Q*1*J1`*1#*c1o*1"*M1`1*"1`*V1*1V*`1* 1Y*Q*1#1B*V1*6o/H/6!6T/J6/%6f/J/6$/O6i6/$6i/O/6!6V/B/66Y/T/66M/:/6"8u1M1 88T1Y188}1O181f8E81$1Q8Y18#8o1r1881o18 8o1o18ÿ/MTrk˜ÿ!ÿ Muted GuitarÇ·^· P·[@]@’\—@lu@@u@@lu@@u@@u@@u@@u@@u@@u@@u@@u@@ru@@u@@u@@u@@u@@u@@~u@@fu@@u@@xu@@u@@fu@@u@@xu@@u@@{u@@xu@@xu@@u@@u@@u@¥BluBBuBBluBBuBBuBBuBBuBBuBBuBBuBBuBBruBBuBBuBBuBBuBBuBB~uBBfuBBuBBxuBBuBBfuBBuBBxuBBuBB{uBBxuBÿ/MTrkÿ!ÿI Wanna Be Sedatedÿ/MTrkÿ!ÿBy The Ramonesÿ/MTrkÿ!ÿ Sequenced byÿ/MTrk$ÿ!ÿsargepp67@earthlink.netÿ/midifile-0.4.2/LICENSE.txt000066400000000000000000000013041471740550200151250ustar00rootroot00000000000000 midifile Copyright (C) 2006-2015 Martin Peach 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. If not, see . midifile-0.4.2/Makefile000066400000000000000000000007661471740550200147550ustar00rootroot00000000000000# Makefile for midifile lib.name = midifile class.sources = midifile.c datafiles = \ I_Wanna_Be_Sedated.mid \ LICENSE.txt \ README.md \ midifile-help.pd \ midifile-meta.pd # This Makefile is based on the Makefile from pd-lib-builder written by # Katja Vetter. You can get it from: # https://github.com/pure-data/pd-lib-builder PDLIBBUILDER_DIR=pd-lib-builder/ include $(firstword $(wildcard $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder Makefile.pdlibbuilder)) midifile-0.4.2/README.md000066400000000000000000000002361471740550200145640ustar00rootroot00000000000000midifile ======== Read and write MIDI files (.mid). Open midifile-help.pd with Pd to get detailed information about supported methods. Author: Martin Peach midifile-0.4.2/midifile-help.pd000066400000000000000000000337631471740550200163550ustar00rootroot00000000000000#N canvas 583 98 399 237 12; #N canvas 24 112 1136 834 midifile_write 0; #X obj 324 -2 bng 45 250 50 0 empty empty choose 5 23 0 10 #3c50fc #fcac44 #ffffff; #X obj 67 65 tgl 45 0 empty empty record 2 23 0 12 #fc2828 #e8e828 #ffffff 0 1; #X floatatom 553 780 15 0 0 0 tick - - 0; #X obj 67 150 metro 2; #X floatatom 120 125 15 0 0 0 - - - 0; #X msg 120 99 2.005; #X msg 506 590 verbose \$1; #X text 525 544 verbosity defaults to 1; #X obj 324 54 savepanel; #X msg 409 493 240 1 2 3 4 247; #X text 536 492 a sysex message; #X obj 553 750 float; #X floatatom 506 564 5 0 0 0 - - - 0; #X msg 324 408 write \$1 \$2 \$3; #X msg 350 199 29; #X msg 388 199 30; #X msg 235 199 0; #X floatatom 405 275 5 0 0 0 ticks_per_frame - - 0; #X text 80 301 (ticks per quarter note if frames per second is zero); #X msg 312 199 25; #X msg 272 199 24; #X text 79 322 25 20 will give accurate timing with metro ticks at 2ms; #X obj 324 375 pack s 25 20; #X obj 559 663 midifile; #X text 7 199 time code frames per second:; #X text 509 432 default is 90 ticks per quarter note; #X msg 349 433 write filename.mid; #X msg 374 458 write filename.mid 77; #X text 555 457 77 ticks per quarter note; #X msg 442 526 flush; #X obj 268 146 cnv 15 200 20 empty empty empty 20 12 0 14 #f8fc00 #404040 0; #X floatatom 514 145 5 0 0 0 note - - 0; #X floatatom 514 175 5 0 0 0 velocity - - 0; #X obj 558 333 pack 144 0 0; #X obj 577 179 sel 0; #X obj 558 206 t b f; #X obj 558 307 f; #X text 553 565 set to 3 to debug input; #X obj 558 125 notein; #X obj 102 8 cnv 15 220 20 empty empty empty 20 12 0 14 #f8fc00 #404040 0; #X text 104 10 1: open a file for writing:; #X obj 116 64 cnv 15 150 20 empty empty empty 20 12 0 14 #f8fc00 #404040 0; #X text 118 67 2: start recording; #X obj 122 524 cnv 15 300 20 empty empty empty 20 12 0 14 #f8fc00 #404040 0; #X text 130 526 4: stop recording and save the file:; #X floatatom 512 230 5 0 0 0 channel - - 0; #X obj 609 287 +; #X msg 577 235 127; #X msg 609 207 143; #X floatatom 919 103 5 0 0 0 value - - 0; #X floatatom 919 134 5 0 0 0 controller - - 0; #X floatatom 917 183 5 0 0 0 channel - - 0; #X obj 965 83 ctlin; #X obj 965 237 pack 176 0 0; #X obj 965 269 print ctl>; #X obj 579 374 print note>; #X obj 965 119 t b f; #X obj 965 183 f; #X obj 1020 126 + 175; #X text 285 143 3: input MIDI as lists; #X msg 778 551 track \$1; #X msg 971 519 144 60 0; #X msg 882 518 144 60 64; #X msg 863 549 144 67 64; #X msg 953 549 144 67 0; #X obj 778 500 hradio 15 1 0 8 empty empty empty 0 -8 0 10 #fcfcfc #000000 #000000 0; #X obj 708 633 r midiwrite; #N canvas 141 452 1100 497 meta_messages 0; #X text 71 6 FF 51 3 tttttt Set Tempo (in microseconds per MIDI quarter-note); #X obj 539 526 s midiwrite; #X text 407 196 Instrument Name; #X text 399 220 Lyric; #X text 385 126 Text Event (should be at start of track); #X text 224 102 Sequence Number (must be at start of track); #X text 419 150 Copyright Notice; #X text 398 173 Sequence/Track Name; #X msg 372 339 meta 81 500000; #X text 495 338 Set Tempo (microseconds per MIDI quarter-note); #X msg 136 103 meta 0 678; #X text 439 244 Marker; #X text 463 268 Cue Point; #X msg 326 293 meta 32 5; #X text 405 292 MIDI Channel Prefix; #X msg 349 316 meta 47; #X text 414 315 End of Track; #X text 6 42 raw mode; #X text 44 104 meta method; #X msg 74 41 255 81 3 500000; #X text 544 361 SMPTE Offset (hr mi se fr ff); #X msg 395 362 meta 84 0 1 30 4 5; #X text 555 384 Time Signature; #X msg 418 385 meta 88 6 3 36 8; #X msg 441 408 meta 89 0 0; #X text 538 407 Key Signature (number of sharps(+) / flats(-) 0 or 1 for major or minor; #X msg 481 448 meta 127 0 1 22 33 44 55; #X text 683 449 Sequencer-Specific Meta-Event; #X msg 509 476 meta 52; #X text 574 475 unknown; #X msg 230 197 meta 4 twisted_guitar; #X msg 278 245 meta 6 another_part; #X msg 302 269 meta 7 "drops_ball"; #X msg 160 127 meta 1 Some_text_goes_here.; #X msg 184 151 meta 2 (C)2018_Nobody_At_All; #X msg 207 174 meta 3 amazing_sequence; #X msg 254 221 meta 5 "what_the"; #X text 575 143 Underscore will be replaced by space in text metas; #X connect 8 0 1 0; #X connect 10 0 1 0; #X connect 13 0 1 0; #X connect 15 0 1 0; #X connect 19 0 1 0; #X connect 21 0 1 0; #X connect 23 0 1 0; #X connect 24 0 1 0; #X connect 26 0 1 0; #X connect 28 0 1 0; #X connect 30 0 1 0; #X connect 31 0 1 0; #X connect 32 0 1 0; #X connect 33 0 1 0; #X connect 34 0 1 0; #X connect 35 0 1 0; #X connect 36 0 1 0; #X restore 561 87 pd meta_messages; #X obj 506 532 hradio 15 1 0 5 empty empty verbosity 0 -6 0 12 #3c50fc #e8e828 #000000 0; #X obj 174 86 cnv 15 380 20 empty empty empty 20 12 0 14 #f8fc00 #404040 0; #X text 180 86 Maybe add some meta messages before we start:; #X text 780 478 choose track to write; #X text 753 744 Martin Peach \, 2010 - 2018; #X connect 0 0 8 0; #X connect 1 0 3 0; #X connect 3 0 23 0; #X connect 4 0 3 1; #X connect 5 0 4 0; #X connect 6 0 23 0; #X connect 8 0 22 0; #X connect 9 0 23 0; #X connect 11 0 2 0; #X connect 12 0 6 0; #X connect 13 0 23 0; #X connect 14 0 22 1; #X connect 15 0 22 1; #X connect 16 0 22 1; #X connect 17 0 22 2; #X connect 19 0 22 1; #X connect 20 0 22 1; #X connect 22 0 13 0; #X connect 23 1 11 1; #X connect 23 2 11 0; #X connect 26 0 23 0; #X connect 27 0 23 0; #X connect 29 0 23 0; #X connect 33 0 23 0; #X connect 33 0 55 0; #X connect 34 0 47 0; #X connect 34 1 48 0; #X connect 35 0 36 0; #X connect 35 1 33 1; #X connect 36 0 33 0; #X connect 38 0 31 0; #X connect 38 0 35 0; #X connect 38 1 32 0; #X connect 38 1 34 0; #X connect 38 1 33 2; #X connect 38 2 45 0; #X connect 38 2 46 1; #X connect 46 0 36 1; #X connect 47 0 46 0; #X connect 48 0 46 0; #X connect 52 0 49 0; #X connect 52 0 56 0; #X connect 52 1 50 0; #X connect 52 1 53 1; #X connect 52 2 51 0; #X connect 52 2 58 0; #X connect 53 0 54 0; #X connect 53 0 23 0; #X connect 56 0 57 0; #X connect 56 1 53 2; #X connect 57 0 53 0; #X connect 58 0 57 1; #X connect 60 0 23 0; #X connect 61 0 23 0; #X connect 62 0 23 0; #X connect 63 0 23 0; #X connect 64 0 23 0; #X connect 65 0 60 0; #X connect 66 0 23 0; #X connect 68 0 12 0; #X restore 76 116 pd midifile_write; #N canvas 240 205 914 702 midifile_read 0; #X obj 544 149 bng 15 250 50 0 empty empty step_one_tick 18 7 0 12 #0400fc #f8fc00 #000000; #X obj 12 69 openpanel; #X obj 12 16 bng 45 250 50 0 empty empty choose 3 23 0 12 #3c50fc #fcac44 #fc2828; #X obj 116 151 tgl 45 0 empty empty play -45 23 0 12 #14e814 #000000 #fc2828 0 1; #X msg 391 478 rewind; #X text 235 477 go to start of file; #X floatatom 461 570 15 0 0 0 current_tick - - 0; #X obj 235 301 hradio 15 1 0 16 empty empty dump_track_number 0 -6 0 12 #3c50fc #e8e828 #000000 0; #X msg 235 322 dump \$1; #X msg 354 441 68050; #X msg 179 266 track \$1; #X obj 179 226 hradio 15 1 0 16 empty empty play_track_number 0 -6 0 12 #3c50fc #e8e828 #000000 0; #X obj 116 203 metro 2; #X text 193 542 creation arguments: midi_file_name; #X text 298 321 parse this track to main window; #X floatatom 709 660 15 0 0 0 last_tick - - 0; #X msg 311 398 verbose \$1; #X text 123 398 verbosity defaults to 1; #X text 63 11 1: choose a MIDI file to play; #X text 169 145 2: start playing it; #X obj 435 424 spigot; #X obj 480 390 tgl 25 0 empty empty loop -45 12 0 12 #0400fc #f8fc00 #fc0400 0 1; #X msg 12 99 read \$1; #X floatatom 311 374 5 0 0 0 - - - 0; #X obj 311 355 hradio 15 1 0 5 empty empty verbosity 0 -6 0 12 #3c50fc #e8e828 #000000 0; #X obj 179 243 - 1; #X obj 65 505 ctlout 123; #X msg 65 475 123; #X msg 39 126 read I_Wanna_Be_Sedated.mid; #X obj 65 447 bng 15 250 50 0 empty empty all_notes_off 17 7 0 10 #fc0400 #f8fc00 #000000; #X obj 718 590 t b b; #X floatatom 134 263 5 0 0 0 - - - 0; #X obj 750 617 bng 15 250 50 0 empty empty end 17 7 0 10 #fc0400 #f8fc00 #000000; #X floatatom 632 433 9 0 0 0 loop_start_tick: - - 0; #X text 214 243 -1 = play all tracks; #X obj 709 638 f; #X obj 435 450 f 0; #N canvas 302 192 1058 571 route_events 0; #X obj 20 29 inlet; #X floatatom 172 125 5 0 0 0 note - - 0; #X floatatom 249 125 5 0 0 1 velocity - - 0; #X obj 172 50 route 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159, f 80; #X obj 172 103 unpack 0 0; #X obj 178 182 route 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143, f 79; #X obj 76 146 print note_on; #X obj 76 260 print note_off; #X obj 705 261 noteout 1; #X obj 786 261 noteout 2; #X obj 865 261 noteout 3; #X obj 945 261 noteout 4; #X obj 178 289 route 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192, f 80; #X floatatom 178 347 5 0 0 0 controller - - 0; #X floatatom 252 347 5 0 0 1 value - - 0; #X obj 178 323 unpack 0 0; #X obj 52 372 print controller; #X obj 706 359 ctlout 1; #X text 172 30 route note-on events by channel:; #X text 235 162 route note off events by channel:; #X text 225 265 route controller events by channel:; #X text 505 262 send events to MIDI devices:; #X obj 179 423 route 240; #X obj 179 502 print sysex; #X obj 76 118 spigot; #X obj 95 24 inlet; #X obj 23 71 tgl 15 0 empty empty print_status_names 17 7 0 10 #00fc04 #000000 #000000 0 1; #X obj 77 232 spigot; #X obj 52 345 spigot; #X obj 179 463 spigot; #X obj 239 463 spigot; #X obj 266 502 print sys; #X text 505 359 send events to MIDI devices:; #X obj 776 359 ctlout 2; #X obj 846 359 ctlout 3; #X obj 916 359 ctlout 4; #X connect 0 0 3 0; #X connect 3 0 4 0; #X connect 3 0 8 0; #X connect 3 0 24 0; #X connect 3 1 9 0; #X connect 3 2 10 0; #X connect 3 3 11 0; #X connect 3 16 5 0; #X connect 4 0 1 0; #X connect 4 1 2 0; #X connect 5 0 8 0; #X connect 5 0 27 0; #X connect 5 1 9 0; #X connect 5 2 10 0; #X connect 5 3 11 0; #X connect 5 16 12 0; #X connect 12 0 15 0; #X connect 12 0 17 0; #X connect 12 0 28 0; #X connect 12 1 33 0; #X connect 12 2 34 0; #X connect 12 3 35 0; #X connect 12 17 22 0; #X connect 15 0 13 0; #X connect 15 1 14 0; #X connect 22 0 29 0; #X connect 22 1 30 0; #X connect 24 0 6 0; #X connect 25 0 26 0; #X connect 26 0 24 1; #X connect 26 0 27 1; #X connect 26 0 28 1; #X connect 26 0 29 1; #X connect 26 0 30 1; #X connect 27 0 7 0; #X connect 28 0 16 0; #X connect 29 0 23 0; #X connect 30 0 31 0; #X restore 435 593 pd route_events; #N canvas 114 197 1088 523 route_info 0; #X obj 34 13 inlet; #X floatatom 34 73 3 0 0 1 format - - 0; #X floatatom 142 73 5 0 0 1 tracks - - 0; #X floatatom 252 73 5 0 0 1 ticks_per_quarternote - - 0; #X floatatom 360 140 5 0 0 1 tracks - - 0; #X symbolatom 546 190 40 0 0 0 - - - 0; #X obj 538 224 unpack 0 0; #X floatatom 615 278 15 0 0 0 last_tick - - 0; #X floatatom 538 250 5 0 0 1 track - - 0; #X floatatom 449 190 5 0 0 1 track - - 0; #X obj 449 164 unpack 0 s; #X obj 627 316 unpack 0 0 0 0; #X floatatom 627 352 3 0 0 1 / - - 0; #X floatatom 663 353 3 0 0 1 - - - 0; #X floatatom 699 353 5 0 0 1 clocks_per_click - - 0; #X floatatom 736 379 5 0 0 1 32nds_per_quarternote - - 0; #X floatatom 716 136 15 0 0 0 microsec_per_quarternote - - 0; #X obj 229 354 /; #X floatatom 442 374 15 0 0 0 microsec_per_tick - - 0; #X obj 229 395 / 1000; #X floatatom 229 426 15 0 0 0 millisec_per_tick - - 0; #X obj 906 190 print other_meta; #X obj 360 103 route seq_num name end time_sig microsec_per_quarternote; #X obj 805 161 route key_sig; #X obj 805 218 unpack 0 0 s; #X symbolatom 898 323 10 0 0 0 key - - 0; #X floatatom 805 247 5 0 0 1 +sharps/-flats - - 0; #X obj 851 276 tgl 15 0 empty empty minor 17 7 0 10 #fcfcfc #000000 #000000 0 1; #X obj 546 164 list prepend; #X obj 898 297 list prepend; #X obj 34 43 route format tracks ticks_per_quarternote; #X obj 228 477 s msec_per_tick; #X obj 405 211 print name:; #X text 503 352 time signature:; #X connect 0 0 30 0; #X connect 6 0 8 0; #X connect 6 1 7 0; #X connect 10 0 9 0; #X connect 10 1 28 0; #X connect 11 0 12 0; #X connect 11 1 13 0; #X connect 11 2 14 0; #X connect 11 3 15 0; #X connect 17 0 18 0; #X connect 17 0 19 0; #X connect 19 0 20 0; #X connect 19 0 31 0; #X connect 22 0 4 0; #X connect 22 1 10 0; #X connect 22 1 32 0; #X connect 22 2 6 0; #X connect 22 3 11 0; #X connect 22 4 16 0; #X connect 22 4 17 0; #X connect 22 5 23 0; #X connect 23 0 24 0; #X connect 23 1 21 0; #X connect 24 0 26 0; #X connect 24 1 27 0; #X connect 24 2 29 0; #X connect 28 0 5 0; #X connect 29 0 25 0; #X connect 30 0 1 0; #X connect 30 1 2 0; #X connect 30 2 3 0; #X connect 30 2 17 1; #X connect 30 3 22 0; #X restore 785 589 pd route_info; #X obj 718 562 route bang; #X text 222 441 goto tick 68050:; #X obj 386 147 r msec_per_tick; #X floatatom 386 186 9 0 0 0 - - - 0; #X text 81 593 MIDI messages are output on first outlet as lists:; #X text 386 108 milliseconds per tick is calculated from metadata at start of file. Step one tick to get the initial value.; #X obj 435 542 midifile; #X text 548 541 meta data \, bang at end of file on third outlet; #X obj 573 578 tgl 15 1 empty empty print_status_names 17 7 0 10 #00fc04 #000000 #000000 0 1; #X text 728 676 Martin Peach \, 2011-2020; #X connect 0 0 45 0; #X connect 1 0 22 0; #X connect 2 0 1 0; #X connect 3 0 12 0; #X connect 4 0 45 0; #X connect 7 0 8 0; #X connect 8 0 45 0; #X connect 9 0 45 0; #X connect 10 0 45 0; #X connect 11 0 25 0; #X connect 12 0 45 0; #X connect 16 0 45 0; #X connect 20 0 36 0; #X connect 21 0 20 1; #X connect 22 0 45 0; #X connect 23 0 16 0; #X connect 24 0 23 0; #X connect 25 0 10 0; #X connect 25 0 31 0; #X connect 27 0 26 0; #X connect 28 0 45 0; #X connect 29 0 27 0; #X connect 30 0 20 0; #X connect 30 1 35 0; #X connect 30 1 32 0; #X connect 33 0 36 1; #X connect 35 0 15 0; #X connect 36 0 45 0; #X connect 39 0 30 0; #X connect 39 1 38 0; #X connect 41 0 42 0; #X connect 42 0 12 1; #X connect 45 0 37 0; #X connect 45 1 6 0; #X connect 45 1 35 1; #X connect 45 2 39 0; #X connect 47 0 37 1; #X restore 76 83 pd midifile_read; #X text 15 10 midifile reads and writes MIDI files.; #N canvas 403 187 587 265 META 0; #X text 12 185 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 165 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control MIDI; #X text 12 45 DESCRIPTION read and write MIDI files; #X text 12 105 OUTLET_0 list; #X text 12 125 OUTLET_1 float; #X text 12 65 INLET_0 bang float list rewind read track dump verbose write meta flush; #X text 12 145 OUTLET_2 bang \, list; #X restore 335 202 pd META; #X text 148 203 2020/06/10 Martin Peach; midifile-0.4.2/midifile-meta.pd000066400000000000000000000004251471740550200163400ustar00rootroot00000000000000#N canvas 18 240 200 200 10; #N canvas 604 86 420 300 META 0; #X text 7 60 VERSION 0.4; #X text 6 86 AUTHOR Martin Peach; #X text 8 14 NAME midifile; #X text 7 112 LICENSE GNU GPL v2+; #X text 6 37 DESCRIPTION read and write binary MIDI files (.mid); #X restore 10 10 pd META; midifile-0.4.2/midifile.c000066400000000000000000002503021471740550200152340ustar00rootroot00000000000000/** \mainpage midifile.c An external for Pure Data that reads and writes MIDI files * * Copyright (C) 2005-2020 Martin Peach * \section license * 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 * 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; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Latest version of this file can be found at: * http://pure-data.svn.sourceforge.net/viewvc/pure-data/trunk/externals/mrpeach/midifile/ * */ #include "m_pd.h" #include #include #include // for uint32_t #include /* support older Pd versions without sys_open(), sys_fopen(), sys_fclose() */ #if PD_MAJOR_VERSION == 0 && PD_MINOR_VERSION < 44 #define sys_open open #define sys_fopen fopen #define sys_fclose fclose #endif #define NO_MORE_ELEMENTS 0xFFFFFFFF static t_class *midifile_class; #define PATH_BUF_SIZE 1024 #define MAX_TRACKS 128 /* track data is allocated as needed but we need to preallocate space for the pointers */ #define ALL_TRACKS MAX_TRACKS /** [midifile] can be in one of three states: - mfReset: set by midifile_new() and midifile_clode() - mfReading: set by midifile_new() and midifile_read() if a file has been opened - mfWriting: set by midifile_write() if a file has been opened */ typedef enum {mfReset, mfReading, mfWriting} mfstate; typedef struct mf_header_chunk { char chunk_type[4]; /* each chunk begins with a 4-character ASCII type.*/ uint32_t chunk_length ; /* followed by a 32-bit length */ int chunk_format; int chunk_ntrks; int chunk_division; } mf_header_chunk; typedef struct mf_track_chunk { char chunk_type[4]; /* each chunk begins with a 4-character ASCII type. */ uint32_t chunk_length; /* followed by a 32-bit length */ uint32_t delta_time; /* current delta_time of latest track_data element */ uint32_t total_time; /* sum of delta_times so far */ uint32_t track_index; /* current byte offset to next track_data element */ int track_ended; /* non-zero if track has finished */ unsigned char running_status; unsigned char *track_data; } mf_track_chunk; typedef struct t_midifile { t_object x_obj; /** current time for this MIDI file in delta_time units */ uint32_t total_time; /** one MIDI packet as a list */ t_atom midi_data[3]; t_outlet *midi_list_outlet; t_outlet *status_outlet; t_outlet *total_time_outlet; /** a file for reading or writing */ FILE *fP; /** potentially lots of tracks may be written */ FILE *tmpFP[MAX_TRACKS]; /** current directory for relative file paths */ t_symbol *our_directory; /** absolute path to file at fP */ char fPath[PATH_BUF_SIZE]; /** character offset into the file fP */ uint32_t offset; /** play this track, or all tracks if negative. Write to this track */ int track; /** nonzero for text output to console */ int verbosity; /** nonzero if all tracks have finished */ int ended; /** mfReset, mfReading, or mfWriting */ mfstate state; /** First chunk in the midi file */ mf_header_chunk header_chunk; /** Subsequent track chunks. Other kinds of chunk are ignored. */ mf_track_chunk track_chunk[MAX_TRACKS]; } t_midifile; static void midifile_skip_next_track_chunk_data(t_midifile *x, int mfTrack); static void midifile_get_next_track_chunk_data(t_midifile *x, int mfTrack); static uint32_t midifile_get_next_track_chunk_delta_time(t_midifile *x, int mfTrack); static void midifile_output_long_list (t_outlet *outlet, unsigned char *cP, uint32_t len, unsigned char first_byte); static void midifile_dump_track_chunk_data(t_midifile *x, int mfTrack); static unsigned char *midifile_read_var_len (unsigned char *cP, uint32_t *delta); static int midifile_write_variable_length_value (FILE *fP, uint32_t value); static unsigned short midifile_combine_bytes(unsigned char data1, unsigned char data2); static unsigned short midifile_get_multibyte_2(unsigned char n[2]); static unsigned long midifile_get_multibyte_3(unsigned char n[3]); static unsigned long midifile_get_multibyte_4(unsigned char n[4]); static int midifile_read_track_chunk(t_midifile *x, int mfTrack); static int midifile_read_header_chunk(t_midifile *x); static void midifile_rewind (t_midifile *x); static void midifile_rewind_tracks(t_midifile *x); static int midifile_read_chunks(t_midifile *x); static void midifile_close(t_midifile *x); static void midifile_free_file(t_midifile *x); static void midifile_free(t_midifile *x); static int midifile_open_path(t_midifile *x, const char *path, char *mode); static void midifile_flush(t_midifile *x); static uint32_t midifile_write_header(t_midifile *x, int nTracks); static void midifile_read(t_midifile *x, t_symbol *path); static void midifile_write(t_midifile *x, t_symbol *s, int argc, t_atom *argv); static int midifile_write_delta_time(t_midifile *x); static void midifile_meta(t_midifile *x, t_symbol *s, int argc, t_atom *argv); static void midifile_bang(t_midifile *x); static FILE *midifile_open_track_file(t_midifile *x, int trackNr); static int midifile_delete_track_file(t_midifile *x, int trackNr); static uint32_t midifile_write_end_of_track(t_midifile *x, uint32_t end_time, int trackNr); static void midifile_float(t_midifile *x, t_float ticks); static void midifile_list(t_midifile *x, t_symbol *s, int argc, t_atom *argv); static void *midifile_new(t_symbol *s, int argc, t_atom *argv); static void midifile_verbosity(t_midifile *x, t_floatarg verbosity); static void midifile_set_track(t_midifile *x, t_floatarg track); static void midifile_dump(t_midifile *x, t_floatarg track); static t_symbol *midifile_key_name(int sf, int mi); void midifile_setup(void); /** midifile_setup instantiates an instance of [midifile] - calls class_new() to register midifile_new() as the constructor and midifile_free() as the destructor * Registers methods: - midifile_bang() - midifile_float() - midifile_list() - midifile_read() - midifile_flush() - midifile_write() - midifile_dump() - midifile_set_track() - midifile_rewind() - midifile_verbosity() */ void midifile_setup(void) { const char aStr[] = "midifile v0.4 20200321 by Martin Peach"; midifile_class = class_new (gensym("midifile"), (t_newmethod) midifile_new, (t_method)midifile_free, sizeof(t_midifile), CLASS_DEFAULT, A_GIMME, 0); class_addbang(midifile_class, midifile_bang); class_addfloat(midifile_class, midifile_float); class_addlist(midifile_class, midifile_list); class_addmethod(midifile_class, (t_method)midifile_read, gensym("read"), A_DEFSYMBOL, 0); class_addmethod(midifile_class, (t_method)midifile_flush, gensym("flush"), 0); class_addmethod(midifile_class, (t_method)midifile_write, gensym("write"), A_GIMME, 0); class_addmethod(midifile_class, (t_method)midifile_meta, gensym("meta"), A_GIMME, 0); class_addmethod(midifile_class, (t_method)midifile_dump, gensym("dump"), A_DEFFLOAT, 0); class_addmethod(midifile_class, (t_method)midifile_set_track, gensym("track"), A_DEFFLOAT, 0); class_addmethod(midifile_class, (t_method)midifile_rewind, gensym("rewind"), 0); class_addmethod(midifile_class, (t_method)midifile_verbosity, gensym("verbose"), A_DEFFLOAT, 0); #if PD_MAJOR_VERSION==0 && PD_MINOR_VERSION<43 post(aStr); #else logpost(NULL, 3, "%s", aStr); #endif } /** midifile_new is called from Pd when a new [midifile] is being instantiated. * - Initializes the state of this [midifile]. - An optional argument is a file name that will be opened here. - Adds outlets for midi_list, total_time, and status. */ static void *midifile_new(t_symbol *s, int argc, t_atom *argv) { t_midifile *x = (t_midifile *)pd_new(midifile_class); t_symbol *pathSymbol; int i; (void)s; /* silence unused param warning */ x->fP = NULL; x->fPath[0] = '\0'; x->our_directory = canvas_getcurrentdir();/* get the current directory to use as the base for relative file paths */ x->track = ALL_TRACKS; /* startup playing anything */ x->midi_data[0].a_type = x->midi_data[1].a_type = x->midi_data[2].a_type = A_FLOAT; x->state = mfReset; x->verbosity = 1; /* default to posting all */ for (i = 0; i < MAX_TRACKS; ++i) { x->track_chunk[i].track_data = NULL; x->track_chunk[i].track_ended = 0; } /* find the first string in the arg list and interpret it as a path to a midi file */ for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_SYMBOL) { pathSymbol = atom_getsymbol(&argv[i]); if (pathSymbol != NULL) { if (midifile_open_path(x, pathSymbol->s_name, "rb")) { if (x->verbosity) post("midifile: opened %s", x->fPath); x->state = mfReading; if (midifile_read_chunks(x) == 0) midifile_free_file(x); } else pd_error(NULL, "midifile: unable to open %s", pathSymbol->s_name); break; } } } x->midi_list_outlet = outlet_new(&x->x_obj, &s_list); x->total_time_outlet = outlet_new(&x->x_obj, &s_float); /* current total_time */ x->status_outlet = outlet_new(&x->x_obj, &s_anything);/* last outlet for everything else */ return (void *)x; } /** midifile_close closes the file and its associated temp files. - calls sys_fclose, midifile_delete_track_file, and sets x->fP and all x->tmpFp[]s to NULL - clears x->fPath[0] - sets x->state to mfReset - resets x->totalTime and x->offset - outputs new totalTime from x->total_time_outlet */ static void midifile_close(t_midifile *x) { int i; if (x->fP != NULL) { sys_fclose (x->fP); x->fP = NULL; } for (i = 0; i < MAX_TRACKS; ++i) { if (x->tmpFP[i] != NULL) { sys_fclose(x->tmpFP[i]); midifile_delete_track_file(x, i); x->tmpFP[i] = NULL; } } x->fPath[0] = '\0'; x->state = mfReset; x->total_time = 0L; x->offset = 0L; outlet_float(x->total_time_outlet, x->total_time); } /** midifile_free_file closes the file and its associated tracks. - calls midifile_close() and frees all track data */ static void midifile_free_file(t_midifile *x) { int i; midifile_close(x); for (i = 0; i < MAX_TRACKS; ++i) { if (x->track_chunk[i].track_data != NULL) freebytes(x->track_chunk[i].track_data, x->track_chunk[i].chunk_length); x->track_chunk[i].track_data = NULL; x->track_chunk[i].track_ended = 0; } } /** midifile_free closes all files and frees all allocated memory. - calls midifile_free_file(). */ static void midifile_free(t_midifile *x) { midifile_free_file(x); } /** midifile_open_path attempts to open a file. - path is a string. - Up to PATH_BUF_SIZE-1 characters will be copied into x->fPath. - mode should be "rb" or "wb". - x->fPath will be used as a file name to open. - Returns 1 if successful, else 0. */ static int midifile_open_path(t_midifile *x, const char *path, char *mode) { FILE *fP = NULL; char tryPath[PATH_BUF_SIZE]; char slash[] = "/"; /* If the first character of the path is a slash then the path is absolute */ /* On MSW if the second character of the path is a colon then the path is absolute */ if ((path[0] == '/') || (path[0] == '\\') || (path[1] == ':')) { strncpy(tryPath, path, PATH_BUF_SIZE-1); /* copy path into a length-limited buffer */ /* ...if it doesn't work we won't mess up x->fPath */ tryPath[PATH_BUF_SIZE-1] = '\0'; /* just make sure there is a null termination */ if (x->verbosity > 1)post("midifile_open_path (absolute): %s\n", tryPath); fP = sys_fopen(tryPath, mode); } if (fP == NULL) { /* Then try to open the path from the current directory */ strncpy(tryPath, x->our_directory->s_name, PATH_BUF_SIZE - 1); /* copy path into a length-limited buffer */ strncat(tryPath, slash, PATH_BUF_SIZE-1); /* copy path into a length-limited buffer */ strncat(tryPath, path, PATH_BUF_SIZE - 1); /* copy path into a length-limited buffer */ /* ...if it doesn't work we won't mess up x->fPath */ tryPath[PATH_BUF_SIZE-1] = '\0'; /* just make sure there is a null termination */ if (x->verbosity > 1)post("midifile_open_path (relative): %s\n", tryPath); fP = sys_fopen(tryPath, mode); } if (fP == NULL) return 0; x->fP = fP; strncpy(x->fPath, tryPath, PATH_BUF_SIZE); return 1; } /** midifile_flush writes the header to x->fP, copies the contents of x->tmpFP[] into it, and closes both files. - flush ends the track. - returns immediately unless x->state is mfWriting. - sends a bang to status_outlet so tick count can be captured. - calls midifile_write_header() - calls midifile_write_end_of_track() for each active track. - calls midifile_close(). */ static void midifile_flush(t_midifile *x) { uint32_t written = 0L; uint32_t end_time = x->total_time; uint32_t len; int c, i, k, nTracks = 0; if(x->state != mfWriting) return; /* only if we're writing */ outlet_bang(x->status_outlet); /* bang so tick count can be saved externally */ /* First count the active tracks*/ for (i = 0; i < MAX_TRACKS; ++i) if (x->tmpFP[i] != NULL) ++nTracks; /* Next write the header for the entire file */ written += midifile_write_header(x, nTracks); for (i = 0; i < MAX_TRACKS; ++i) { if (x->tmpFP[i] != NULL) { ++nTracks; if (0 == x->track_chunk[i].track_ended) written += midifile_write_end_of_track(x, end_time, i); /* now copy the MIDI data from tmpFP[i] to fP */ rewind (x->tmpFP[i]); /* write track chunk header followed by the track data */ fprintf (x->fP, "MTrk"); len = x->track_chunk[i].chunk_length; /* length of MIDI data */ for (k = 0; k < 4; ++k) { /* msb first */ c = (char)((len & 0xFF000000)>>24); putc(c, x->fP); len <<= 8; } while ((c = fgetc(x->tmpFP[i])) != EOF) { putc(c, x->fP); ++written; } } } if (x->verbosity) post ("midifile: wrote %lu to %s", written, x->fPath); midifile_close(x); } /** midifile_write_header writes the MThd and MTrk headers to x->fP. - returns the number of bytes written to x->fP. */ static uint32_t midifile_write_header(t_midifile *x, int nTracks) { uint32_t j, written = 0L; int i; char c; rewind (x->fP); fprintf (x->fP, "MThd"); j = 6; /* length of header data */ for (i = 0; i < 4; ++i) { /* msb first */ c = (char)((j & 0xFF000000)>>24); putc(c, x->fP); j <<= 8; } j = (nTracks > 1)?1:0; /* type of file */ /* msb first */ c = (char)((j & 0xFF00)>>8); putc(c, x->fP); c = (char)(j & 0x0FF); putc(c, x->fP); j = nTracks; /* number of tracks */ /* msb first */ c = (char)((j & 0xFF00)>>8); putc(c, x->fP); c = (char)(j & 0x0FF); putc(c, x->fP); j = x->header_chunk.chunk_division; /* ticks per quarter note */ /* msb first */ c = (char)((j & 0xFF00)>>8); putc(c, x->fP); c = (char)(j & 0x0FF); putc(c, x->fP); written = 18L;//22L; return written; } /** midifile_open_track_file opens a temporary file for one track's data * - opens a file for reading and writing in the same directory as the main file. - filename is built from the main filename, trackNr and ".trk" */ static FILE *midifile_open_track_file(t_midifile *x, int trackNr) { int i; char trackPath[PATH_BUF_SIZE]; FILE *fP; strncpy(trackPath, x->fPath, PATH_BUF_SIZE); if (x->verbosity > 2) post("midifile_open_track_file: main file path is %s", trackPath); i = (int)strlen(trackPath); sprintf(&trackPath[i], "%d.trk", trackNr); if (x->verbosity > 2) post("midifile_open_track_file: track path is %s", trackPath); fP = sys_fopen(trackPath, "w+b"); if (NULL == fP) pd_error(x, "Unable to open track file"); return fP; } /** midifile_delete_track_file erases the temporary file for one track's data * - filename is built from the main filename, trackNr and ".trk" */ static int midifile_delete_track_file(t_midifile *x, int trackNr) { int i; char trackPath[PATH_BUF_SIZE]; int result; strncpy(trackPath, x->fPath, PATH_BUF_SIZE); if (x->verbosity > 2) post("midifile_delete_track_file: main file path is %s", trackPath); i = (int)strlen(trackPath); sprintf(&trackPath[i], "%d.trk", trackNr); if (x->verbosity > 2) post("midifile_delete_track_file: \"%s\"", trackPath); result = remove(trackPath); if (0 != result) { result = errno; pd_error(x, "Unable to delete track file \"%s\": %s", trackPath, strerror(result)); } return result; } /** midifile_write implements the write message. * - opens the file for writing and writes the header. - first element of list must be a pathname symbol - optional second argument: ticks_per_frame or frames_per_second - optional third argument: ticks_per_frame - calls midifile_free_file() to clear any previous file data - calls midifile_open_path() - calls midifile_rewind_tracks() */ static void midifile_write(t_midifile *x, t_symbol *s, int argc, t_atom *argv) { char *path = NULL; int frames_per_second = 0;/* default */ int ticks_per_frame = 90; /* default*/ (void)s; /* silence unused param warning */ if ((argc >= 1) && (argv[0].a_type == A_SYMBOL)) path = (char *)argv[0].a_w.w_symbol->s_name; else pd_error(x, "midifile_write: No valid path name"); if (argc == 2) { if (argv[1].a_type == A_FLOAT) ticks_per_frame = (int)argv[1].a_w.w_float; else pd_error (x, "midifile_write: second argument is not a float"); } else if (argc >= 3) /* ignore extra arguments */ { if (argv[2].a_type == A_FLOAT) ticks_per_frame = (int)argv[2].a_w.w_float; else pd_error (x, "midifile_write: third argument is not a float"); if (argv[1].a_type == A_FLOAT) frames_per_second = (int)argv[1].a_w.w_float; else pd_error (x, "midifile_write: second argument is not a float"); } post("midifile_write: path = %s, fps = %d, tpf = %d", path, frames_per_second, ticks_per_frame); midifile_free_file(x); if (midifile_open_path(x, path, "wb")) { if (x->verbosity) post("midifile: opened %s", x->fPath); x->state = mfWriting; x->track = 0; /* write to first track */ x->tmpFP[x->track] = midifile_open_track_file(x, x->track);//tmpfile(); /* a temporary file for the MIDI data while we don't know how long it is */ x->header_chunk.chunk_type[0] = 'M'; x->header_chunk.chunk_type[1] = 'T'; x->header_chunk.chunk_type[2] = 'h'; x->header_chunk.chunk_type[3] = 'd'; x->header_chunk.chunk_length = 6L; /* 3 ints to follow */ x->header_chunk.chunk_format = 0; /* single-track file so far */ x->header_chunk.chunk_ntrks = 1; /* one track for type 0 file */ x->header_chunk.chunk_division = (((-frames_per_second)<<8)|ticks_per_frame); x->track_chunk[0].chunk_type[0] = 'M'; x->track_chunk[0].chunk_type[0] = 'T'; x->track_chunk[0].chunk_type[0] = 'r'; x->track_chunk[0].chunk_type[0] = 'k'; x->track_chunk[0].chunk_length = 0L; /* for now */ midifile_rewind_tracks(x); } else pd_error(x, "midifile_write: Unable to open %s", path); } /** midifile_write_delta_time writes the current delta time to the current track * - returns number of bytes written - calls midifile_write_variable_length_value() */ static int midifile_write_delta_time(t_midifile *x) { /* deltatime */ x->track_chunk[x->track].delta_time = x->total_time - x->track_chunk[x->track].total_time; x->track_chunk[x->track].total_time = x->total_time; return midifile_write_variable_length_value(x->tmpFP[x->track], x->track_chunk[x->track].delta_time); } /** midifile_begin_meta writes the first part of a meta message to the current track of the open file. * - First argument is the midifile object - Second arg is the meta type */ static int midifile_begin_meta(t_midifile *x, int metaType) { int n = midifile_write_delta_time(x); putc (0xFF, x->tmpFP[x->track]); // Meta Status putc (metaType, x->tmpFP[x->track]); // Meta Type return n+2; } /** midifile_meta attempts to add the arguments as a meta event to the current track of the open file. * - First argument is the event ID - Subsequent args are parameters for the specific meta avent - calls midifile_write_delta_time and midifile_begin_meta */ static void midifile_meta(t_midifile *x, t_symbol *s, int argc, t_atom *argv) { int i, j, metaType; long jj; uint32_t nbWritten = 0L; int paramBuf[5]; char *sPtr; char c; uint32_t len; (void)s; /* silence unused param warning */ if ((x->state != mfWriting) || (x->tmpFP[x->track] == NULL)) { /* list only works for writing */ pd_error (x, "midifile_meta: no file is open for writing"); return; } if (0 != x->track_chunk[x->track].track_ended) { /* list only works for writing */ pd_error (x, "midifile_meta: track %d is ended", x->track); return; } if (A_FLOAT != argv[0].a_type) { pd_error (x, "midifile_meta: first argument not an integer on [0..255]"); return; } metaType = (int)atom_getint(&argv[0]); if (x->verbosity > 1) post ("midifile_meta: metaType %d", metaType); switch (metaType) { case 0: /* Sequence Number must be at start of track*/ /* 16-bit sequence number stored bigendian */ /* len is always 02*/ if (x->verbosity > 1) post ("midifile_meta: Sequence Number"); if (argc < 2) { post ("midifile_meta: not enough parameters"); return; } if (A_FLOAT != argv[1].a_type) { post ("midifile_meta: parameter not a number"); return; } j = (int)atom_getint(&argv[1]); if (x->verbosity > 1) post ("midifile_meta: Sequence Number %d", j); nbWritten = midifile_begin_meta(x, metaType); // Sequence Number Meta putc (2, x->tmpFP[x->track]); // len putc (j>>8, x->tmpFP[x->track]); // Sequence Number high byte putc (j%256, x->tmpFP[x->track]); // Sequence Number low byte nbWritten += 3; break; case 1: case 2: case 3: case 4: case 5: case 6: case 7: if (x->verbosity > 1) { if (1 == metaType) post ("midifile_meta: Text Event"); else if (2 == metaType) post ("midifile_meta: Copyright Notice"); else if (3 == metaType) post ("midifile_meta: Sequence/Track Name"); else if (4 == metaType) post ("midifile_meta: Instrument Name"); else if (5 == metaType) post ("midifile_meta: Lyric"); else if (6 == metaType) post ("midifile_meta: Marker"); else if (7 == metaType) post ("midifile_meta: Cue Point"); } /* variable-length len followed by string (spaces must be replaced by underscores to prevent Pd from chopping up into symbols) */ if (argc < 2) { post ("midifile_meta: not enough parameters"); return; } if (argv[1].a_type != A_SYMBOL) { post ("midifile_meta: parameter not a symbol"); return; } sPtr = (char *)argv[1].a_w.w_symbol->s_name; nbWritten = midifile_begin_meta(x, metaType); // a textual Event Meta len = (int)strlen(sPtr); nbWritten += midifile_write_variable_length_value(x->tmpFP[x->track], len); for (jj = 0; jj < len; ++jj) { c = *sPtr++; if (c == '_') c = ' '; // replace underscore with space putc (c, x->tmpFP[x->track]); // text } nbWritten += len; break; case 32: if (x->verbosity > 1) post ("midifile_meta: MIDI Channel Prefix"); /* one-byte channel [0-15] */ /* len is always 01 */ if (argc < 2) { post ("midifile_meta: not enough parameters"); return; } if (A_FLOAT != argv[1].a_type) { post ("midifile_meta: parameter not a number"); return; } j = (int)atom_getint(&argv[1]); if (j <0 || j >15) { post ("midifile_meta: channel number out of range [0-15]"); return; } nbWritten = midifile_begin_meta(x, metaType); // MIDI Channel Prefix Meta putc (1, x->tmpFP[x->track]); // len putc (j, x->tmpFP[x->track]); // channel byte nbWritten += 2; break; case 47: if (x->verbosity > 1) post ("midifile_meta: End of Track"); /* must be the last event */ /* len is always 00 */ nbWritten = midifile_begin_meta(x, metaType); // End of Track Meta putc (0, x->tmpFP[x->track]); // len nbWritten += 1; x->track_chunk[x->track].track_ended = 1; // can't write any more data to this track break; case 81: if (x->verbosity > 1) post ("midifile_meta: Set Tempo"); /* 24-bit microseconds per qurter-note stored bigendian */ /* len is always 3 */ if (argc < 2) { post ("midifile_meta: not enough parameters"); return; } if (A_FLOAT != argv[1].a_type) { post ("midifile_meta: parameter not a number"); return; } jj = (int)atom_getint(&argv[1]); if ((jj < 0) || (jj > 0xFFFFFF)) { post ("midifile_meta: Tempo out of range [0-16777215]"); return; } if (x->verbosity > 1) post ("midifile_meta: Set Tempo %ld", jj); nbWritten = midifile_begin_meta(x, metaType); // Set Tempo Meta putc (3, x->tmpFP[x->track]); // len putc ((jj>>16)&0xFF, x->tmpFP[x->track]); // Set Tempo high byte putc ((jj>>8)&0xFF, x->tmpFP[x->track]); // Set Tempo mid byte putc (jj%256, x->tmpFP[x->track]); // Set Tempo low byte nbWritten += 4; break; case 84: if (x->verbosity > 1) post ("midifile_meta: SMPTE Offset"); /* Should be at time 0 */ /* len is always 5: hr mn se fr ff */ if (argc < 6) { post ("midifile_meta: not enough parameters"); return; } for (i = 1; i < 6; ++i) { if (A_FLOAT != argv[i].a_type) { post ("midifile_meta: parameter %d not a number", i); return; } j = (int)atom_getint(&argv[i]); if ((j < 0) || (j > 127)) { post ("midifile_meta: SMPTE value out of range [0-127]"); // this won't catch all range errors return; } paramBuf[i-1] = j; } nbWritten = midifile_begin_meta(x, metaType); // Set SMPTE Offset Meta putc (5, x->tmpFP[x->track]); // len for (i = 0; i < 5; ++i) { putc (paramBuf[i], x->tmpFP[x->track]); // timecode } nbWritten += 6; break; case 88: if (x->verbosity > 1) post ("midifile_meta: Time Signature"); /* len is always 4: nn dd cc bb */ /* nn=numerator; dd=denominator (as negative power of two: 2=quarter-note */ /* cc=clocks per metronome click; bb=32nd-notes per MIDI quarter-note(24 cloccks) */ if (argc < 5) { post ("midifile_meta: not enough parameters"); return; } for (i = 1; i < 5; ++i) { if (A_FLOAT != argv[i].a_type) { post ("midifile_meta: parameter %d not a number", i); return; } j = (int)atom_getint(&argv[i]); if ((j < 0) || (j > 127)) { post ("midifile_meta: Time Signature value out of range [0-127]"); // this won't catch all range errors return; } paramBuf[i-1] = j; } nbWritten = midifile_begin_meta(x, metaType); // Time Signatre Meta putc (4, x->tmpFP[x->track]); // len for (i = 0; i < 4; ++i) { putc (paramBuf[i], x->tmpFP[x->track]); // time signature } nbWritten += 5; break; case 89: if (x->verbosity > 1) post ("midifile_meta: Key Signature"); /* len is always 2: sf mi */ /* sf = number of sharps (or flats if negative) */ /* mi = 0(major) or 1(minor) */ if (argc < 3) { post ("midifile_meta: not enough parameters"); return; } for (i = 1; i < 3; ++i) { if (A_FLOAT != argv[i].a_type) { post ("midifile_meta: parameter %d not a number", i); return; } j = (int)atom_getint(&argv[i]); if ((i == 1) && ((j < -7) || (j > 7))) { post ("midifile_meta: Key Signature value out of range [-7-+7]"); return; } if ((i == 2) && ((j < 0) || (j > 1))) { post ("midifile_meta: Key Signature value out of range [0-1]"); return; } paramBuf[i-1] = j; } nbWritten = midifile_begin_meta(x, metaType); // Key Signatre Meta putc (2, x->tmpFP[x->track]); // len for (i = 0; i < 2; ++i) { putc (paramBuf[i], x->tmpFP[x->track]); // key signature } nbWritten += 3; break; case 127: if (x->verbosity > 1) post ("midifile_meta: Sequencer-Specific Meta-Event"); /* variable-len followed by stuff */ if (argc < 2) { post ("midifile_meta: not enough parameters"); return; } post ("Sequencer-Specific Meta-Event not implemented yet."); break; default: post("Unknown Meta tag %d", metaType); return; } if (0 != nbWritten) { if (x->verbosity > 1) post("Wrote %lu to track %d", nbWritten, x->track); x->track_chunk[x->track].chunk_length += nbWritten; } } /** midifile_read attempts to open a MIDI file at path. * - calls midifile_open_path() - calls midifile_read_chunks() */ static void midifile_read(t_midifile *x, t_symbol *path) { midifile_free_file(x); if (midifile_open_path(x, path->s_name, "rb")) { if (x->verbosity) post("midifile: opened %s", x->fPath); x->state = mfReading; if (midifile_read_chunks(x) == 0) midifile_free_file(x); // } else pd_error(x, "midifile: Unable to open %s", path->s_name); } /** midifile_bang steps forward one tick and processes all tracks for that tick. * - calls midifile_get_next_track_chunk_delta_time() - calls midifile_get_next_track_chunk_data() - calls midifile_skip_next_track_chunk_data() */ static void midifile_bang(t_midifile *x) { int j, result = 1, ended = 0; uint32_t total_time; switch (x->state) { case mfReading: if (x->verbosity > 3) post("midifile_bang: total_time %lu", x->total_time); for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) { if (x->track_chunk[j].total_time != NO_MORE_ELEMENTS) { while ( ( total_time = midifile_get_next_track_chunk_delta_time(x, j) + x->track_chunk[j].total_time ) == x->total_time ) { if ((x->track == j) ||(x->track == ALL_TRACKS)) midifile_get_next_track_chunk_data(x, j); else midifile_skip_next_track_chunk_data(x, j); } x->ended = 0; } if (x->track_chunk[j].delta_time == NO_MORE_ELEMENTS) ++ended; } if ((ended == x->header_chunk.chunk_ntrks)&&(x->ended == 0)) { /* set ended flag, only bang once */ if (x->verbosity > 1) post ("ended = %d x->header_chunk.chunk_ntrks = %d", ended, x->header_chunk.chunk_ntrks); outlet_bang(x->status_outlet); ++x->ended; } /* falls through */ case mfWriting: ++x->total_time; outlet_float(x->total_time_outlet, x->total_time); break; default: break;/* don't change time when no files are open */ } } /* The arguments of the ``list''-method * a pointer to the class-dataspace * a pointer to the selector-symbol (always &s_list) * the number of atoms and a pointer to the list of atoms: */ /** midifile_list adds a list containing time and midi packet to the temporary file in MIDI file format. * - current track is used to select the temp file. * - calls midifile_write_delta_time() */ static void midifile_list(t_midifile *x, t_symbol *s, int argc, t_atom *argv) { int i, j, k, m = 0, dt_written = 0; uint32_t len, written = 0L; static int warnings = 0; (void)s; /* silence unused param warning */ if (x->state != mfWriting) return;/* list only works for writing */ if (x->tmpFP[x->track] == NULL) { if (0 == warnings++) pd_error (x, "midifile: no file is open for writing"); return; } if (0 != x->track_chunk[x->track].track_ended) { if (0 == warnings++) pd_error (x, "midifile: track %d is ended", x->track); return; } for (i = 0; i < argc; ++i) { if (A_FLOAT == argv[i].a_type) { j = (int)atom_getint(&argv[i]); if (x->verbosity > 2) post ("midifile_list. j[%d] = 0x%lX", i, j); if (j < 0x100) { if (!dt_written) { /* deltatime */ written = midifile_write_delta_time(x); // x->track_chunk[x->track].delta_time = x->total_time - x->track_chunk[x->track].total_time; // x->track_chunk[x->track].total_time = x->total_time; // written = midifile_write_variable_length_value(x->tmpFP[x->track], x->track_chunk[x->track].delta_time); dt_written = 1; } //if (j == x->track_chunk[0].running_status) continue;/* don't save redundant status byte */ if (j >= 0x80 && j <= 0xEF)x->track_chunk[x->track].running_status = j;/* new running status */ else if (j >= 0xF0 && j <= 0xF7) { x->track_chunk[x->track].running_status = 0;/* clear running status */ if (j == 0xF0) { /* system exclusive: */ /* find length */ for (k = i+1, len = 0L; k < argc; ++k, ++len) { if (argv[k].a_type != A_FLOAT) { pd_error (x, "midifile: sysex list must be all floats"); x->track_chunk[x->track].chunk_length += written; return; } m = (int)atom_getint(&argv[k]); if (m & 0x80) break;/* take any non-data as end of exclusive */ } if (m != 0xF7) { pd_error (x, "midifile: sysex list terminator is 0x%X", m); x->track_chunk[x->track].chunk_length += written; return; } ++len; if (x->verbosity) post ("midifile: sysex length %lu. j = 0x%X", len, j); putc (j, x->tmpFP[x->track]); ++written; /* write length as variable length */ written += midifile_write_variable_length_value (x->tmpFP[x->track], len); /* write the rest of the sysex message */ for (k = i+1; j != 0xF7; ++k) { j = (int)atom_getint(&argv[k]); putc (j, x->tmpFP[x->track]); ++written; } x->track_chunk[x->track].chunk_length += written; return; } } if (x->verbosity > 1) post ("midifile: j = 0x%X", j); putc (j, x->tmpFP[x->track]); ++written; } } } x->track_chunk[x->track].chunk_length += written; } /** midifile_write_end_of_track writes an End of Track event to x->tmpFP[trackNr]. - calls midifile_write_variable_length_value() - adds number of bytes written to x->track_chunk[trackNr].chunk_length. - returns number of bytes written. */ static uint32_t midifile_write_end_of_track(t_midifile *x, uint32_t end_time, int trackNr) { uint32_t written = 0; x->track_chunk[trackNr].delta_time = end_time - x->track_chunk[trackNr].total_time; x->track_chunk[trackNr].total_time = x->total_time; written = midifile_write_variable_length_value (x->tmpFP[trackNr], x->track_chunk[trackNr].delta_time); putc (0xFF, x->tmpFP[trackNr]); putc (0x2F, x->tmpFP[trackNr]); putc (0x00, x->tmpFP[trackNr]); written += 3L; x->track_chunk[trackNr].chunk_length += written; return written; } /** midifile_float: Go to a total time of ticks. * if state is mfReading - calls midifile_rewind_tracks() - calls midifile_get_next_track_chunk_delta_time - calls midifile_skip_next_track_chunk_data() if state is mfWriting - sets total_time to ticks If mfReading or mfWriting, outputs new total_time */ static void midifile_float(t_midifile *x, t_float ticks) { uint32_t cTime = (uint32_t)ticks; uint32_t total_time; int j, result = 1, ended = 0; switch (x->state) { case mfReading: /* cue to ticks */ midifile_rewind_tracks(x); for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) { if (x->track_chunk[j].total_time != NO_MORE_ELEMENTS) { while ( ( total_time = midifile_get_next_track_chunk_delta_time(x, j) + x->track_chunk[j].total_time ) < cTime ) midifile_skip_next_track_chunk_data(x, j); } if (x->track_chunk[j].delta_time == NO_MORE_ELEMENTS) ++ended; } x->total_time = cTime; outlet_float(x->total_time_outlet, x->total_time); if (ended == x->header_chunk.chunk_ntrks) { if (x->verbosity) post ("midifile: ended = %d x->header_chunk.chunk_ntrks = %d", ended, x->header_chunk.chunk_ntrks); outlet_bang(x->status_outlet); } break; case mfWriting: /* add ticks to current time */ x->total_time += cTime; outlet_float(x->total_time_outlet, x->total_time); break; case mfReset: /* do nothing */ break; } } /** midifile_read_chunks reads in the MIDI file chunks. * - calls midifile_read_header_chunk() and then - calls midifile_read_track_chunk() for each track */ static int midifile_read_chunks(t_midifile *x) { int j, result; result = midifile_read_header_chunk(x); midifile_rewind_tracks(x); for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) midifile_read_track_chunk(x, j); return result; } /** midifile_read_header_chunk reads the header chunk from an open MIDI file into x->header_chunk. * - calls midifile_get_multibyte_2() - calls midifile_get_multibyte_4() - outputs various file info on the status outlet - Returns 1 on success, else 0 */ static int midifile_read_header_chunk(t_midifile *x) { unsigned char *cP = (unsigned char *)x->header_chunk.chunk_type; char *sP; char buf[4]; uint32_t n; int div, smpte, ticks; t_atom output_atom; if (x->fP == NULL) { pd_error(x, "midifile: no open file"); return 0;/* no open file */ } rewind(x->fP); x->offset = 0L; n = (uint32_t)fread(cP, 1L, 4L, x->fP); x->offset += n; if (n != 4L) { pd_error(x, "midifile: read %d instead of 4", n); return 0; } if (x->verbosity) post("midifile: Header chunk type: %c%c%c%c", cP[0], cP[1], cP[2], cP[3]); if (!(cP[0] == 'M' && cP[1] == 'T' && cP[2] == 'h' && cP[3] == 'd')) { pd_error (x, "midifile: bad file format: bad header chunk type"); return 0; } cP = (unsigned char *)buf; n = (uint32_t)fread(cP, 1L, 4L, x->fP); x->offset += n; if (n != 4L) { pd_error(x, "midifile: read %d instead of 4", n); return 0; } x->header_chunk.chunk_length = (uint32_t)midifile_get_multibyte_4(cP); if (x->verbosity) post("midifile: Header chunk length: %lu", x->header_chunk.chunk_length); if (x->header_chunk.chunk_length != 6L) { pd_error (x, "midifile: bad file format: bad header chunk length"); return 0; } n = (uint32_t)fread(cP, 1L, 2L, x->fP); x->offset += n; if (n != 2L) { pd_error(x, "midifile: read %d instead of 2", n); return 0; } x->header_chunk.chunk_format = midifile_get_multibyte_2(cP); switch (x->header_chunk.chunk_format) { case 0: sP = "Single multichannel track"; break; case 1: sP = "One or more simultaneous tracks"; break; case 2: sP = "One or more sequentially independent single tracks"; break; default: sP = "Unknown format"; } if (x->verbosity) post("midifile: Header chunk format: %d (%s)", x->header_chunk.chunk_format, sP); SETFLOAT(&output_atom, x->header_chunk.chunk_format); outlet_anything( x->status_outlet, gensym("format"), 1, &output_atom); n = (uint32_t)fread(cP, 1L, 2L, x->fP); x->offset += n; if (n != 2L) { pd_error(x, "midifile: read %d instead of 2", n); return 0; } x->header_chunk.chunk_ntrks = midifile_get_multibyte_2(cP); if (x->verbosity) post("midifile: Header chunk ntrks: %d", x->header_chunk.chunk_ntrks); SETFLOAT(&output_atom, x->header_chunk.chunk_ntrks); outlet_anything( x->status_outlet, gensym("tracks"), 1, &output_atom); if (x->header_chunk.chunk_ntrks > MAX_TRACKS) { pd_error (x, "midifile: Header chunk ntrks (%d) exceeds midifile MAX_TRACKS, set to %d", x->header_chunk.chunk_ntrks, MAX_TRACKS); x->header_chunk.chunk_ntrks = MAX_TRACKS; } n = (uint32_t)fread(cP, 1L, 2L, x->fP); x->offset += n; if (n != 2L) { pd_error(x, "midifile: read %d instead of 2", n); return 0; } x->header_chunk.chunk_division = midifile_get_multibyte_2(cP); div = x->header_chunk.chunk_division; if(div & 0x8000) { smpte = (-(div>>8)) & 0x0FF; ticks = div & 0x0FF; if (x->verbosity) post("midifile: Header chunk division: 0x%X: %d frames per second, %d ticks per frame", div, smpte, ticks); SETFLOAT(&output_atom, smpte); outlet_anything( x->status_outlet, gensym("frames_per_sec"), 1, &output_atom); SETFLOAT(&output_atom, ticks); outlet_anything( x->status_outlet, gensym("ticks_per_frame"), 1, &output_atom); } else { if (x->verbosity) post("midifile: Header chunk division: 0x%X: %d ticks per quarter note", div, div); SETFLOAT(&output_atom, div); outlet_anything( x->status_outlet, gensym("ticks_per_quarternote"), 1, &output_atom); } return 1; } /** midifile_read_track_chunk reads the data part of a track chunk into x->track_chunk[mfTrack].track_data * after allocating the space for it. * - calls midifile_get_multibyte_4() - returns 1 on success, else 0 */ static int midifile_read_track_chunk(t_midifile *x, int mfTrack) { unsigned char *cP = (unsigned char *)x->track_chunk[mfTrack].chunk_type; char buf[4]; char type[5]; uint32_t n, len; if (x->fP == NULL) { pd_error(x, "midifile: no open file"); return 0;/* no open file */ } n = (uint32_t)fread(cP, 1L, 4L, x->fP); x->offset += n; if (n != 4L) { pd_error(x, "midifile: read %d instead of 4", n); return 0; } if (!(cP[0] == 'M' && cP[1] == 'T' && cP[2] == 'r' && cP[3] == 'k')) { pd_error (x, "midifile: bad file format: bad track chunk type"); return 0; } type[0] = cP[0]; type[1] = cP[1]; type[2] = cP[2]; type[3] = cP[3]; type[4] = '\0'; cP = (unsigned char *)buf; n = (uint32_t)fread(cP, 1L, 4L, x->fP); x->offset += n; if (n != 4L) { pd_error(x, "midifile: read %d instead of 4", n); return 0; } len = (uint32_t)midifile_get_multibyte_4(cP); x->track_chunk[mfTrack].chunk_length = len; if (x->verbosity) post("midifile: Track chunk %d type: %s, length %d", mfTrack, type, len); if ((cP = getbytes(len)) == NULL) { pd_error (x, "midifile: Unable to allocate %d bytes for track data", len); return 0; } x->track_chunk[mfTrack].track_data = (unsigned char*)cP; n = (uint32_t)fread(cP, 1L, len, x->fP); return 1; } static unsigned short midifile_combine_bytes(unsigned char data1, unsigned char data2) /** make a short from two 7bit MIDI data bytes */ { return ((((unsigned short)data2)<< 7) | ((unsigned short)data1)); } static unsigned long midifile_get_multibyte_4(unsigned char n[4]) /** make a long from 4 consecutive bytes in big-endian format */ { return (((unsigned long)n[0]<<24) + ((unsigned long)n[1]<<16) + ((unsigned long)n[2]<< 8) + ((unsigned long)n[3]<< 0)); } static unsigned long midifile_get_multibyte_3(unsigned char n[3]) /** make a long from 3 consecutive bytes in big-endian format */ { return (((unsigned long)n[0]<<16) + ((unsigned long)n[1]<< 8) + ((unsigned long)n[2]<< 0)); } static unsigned short midifile_get_multibyte_2(unsigned char n[2]) /** make a short from 2 consecutive bytes in big-endian format */ { return (((unsigned long)n[0]<< 8) + ((unsigned long)n[1]<< 0)); } /** midifile_write_variable_length_value writes an integer to the file in variable-length format - returns number of characters written to fP */ static int midifile_write_variable_length_value (FILE *fP, uint32_t value) { uint32_t buffer; int i; char c; buffer = value & 0x07F; while ((value >>= 7) > 0) { buffer <<= 8; buffer |= 0x80; buffer += (value & 0x07F); } i = 0; while (1) { c = (char)(buffer & (0x0FF)); putc(c, fP); ++i; if (buffer & 0x80) buffer >>= 8; else break; } return i; } /** midifile_read_var_len reads a variable-length value from cP into delta. - enter with cP pointing to deltatime. - sets delta to deltatime. - returns pointer to following data. */ static unsigned char *midifile_read_var_len (unsigned char *cP, uint32_t *delta) { unsigned long value; char c; if (((value = *(cP++))) & 0x80) { value &= 0x7f; do { value = (value << 7) + ((c = *(cP++)) & 0x7f); } while (c & 0x80); } *delta = (uint32_t)value; return cP; } /** midifile_verbosity sets the verbosity level of console output. - verbosity can be 0 to 4 - default is 1 */ static void midifile_verbosity(t_midifile *x, t_floatarg verbosity) { x->verbosity = (int)verbosity; post ("midifile verbosity is %d", x->verbosity); } /** midifile_set_track implements the track message. * - sets x->track. * - When reading, play only this track or all tracks if out of range. - When writing, select the track to write to and open a temp file for it unless one is already open. */ static void midifile_set_track(t_midifile *x, t_floatarg track) { if(x->state == mfReading) { /* only if we're reading */ /* anything out of range will be interpreted as all tracks */ if ((track < 0) || (track >= x->header_chunk.chunk_ntrks)) { x->track = ALL_TRACKS; if (x->verbosity>1) post("midifile: playing %d track%s", x->header_chunk.chunk_ntrks, (x->header_chunk.chunk_ntrks>1)?"s":""); } else { x->track = track; if (x->verbosity>1) post("midifile: playing track %d", x->track); } } else if(x->state == mfWriting) { /* only if we're writing */ /* anything out of range will be rejected */ if ((track < 0) || (track >= MAX_TRACKS)) { post ("midifile track not between 0 and %d; using %d.", MAX_TRACKS, x->track); return; } else { x->track = track; // possibly update x->header_chunk.chunk_ntrks if (x->track_chunk[x->track].track_data == NULL) { /* this track is being used for the first time */ post("this track (%d) is being used for the first time", x->track); x->tmpFP[x->track] = midifile_open_track_file(x, x->track);//tmpfile(); /* a temporary file for the MIDI data while we don't know how long it is */ memcpy(x->track_chunk[x->track].chunk_type, "MTrk", 4L); x->track_chunk[x->track].chunk_length = 0L; /* for now */ x->track_chunk[x->track].track_ended = 0; } } } } /** midifile_dump implements the dump message. * - dumps track to console - if track is out of range, dumps all tracks. - calls midifile_dump_track_chunk_data() */ static void midifile_dump(t_midifile *x, t_floatarg track) { int mfTrack = (int)track; if(x->state != mfReading) return; /* only if we're reading */ if ((mfTrack < x->header_chunk.chunk_ntrks) && (mfTrack >= 0)) midifile_dump_track_chunk_data(x, mfTrack); else /* anything out of range will be interpreted as all tracks */ for (mfTrack = 0; mfTrack < x->header_chunk.chunk_ntrks; ++mfTrack) midifile_dump_track_chunk_data(x, mfTrack); } /** midifile_rewind implements the rewind message. * - calls midifile_rewind_tracks() */ static void midifile_rewind (t_midifile *x) { if(x->state != mfReading) return; /* only if we're reading */ midifile_rewind_tracks(x); } /** For all tracks, point to start of track_data */ static void midifile_rewind_tracks(t_midifile *x) { int i; for (i = 0; i < MAX_TRACKS; ++i) { x->track_chunk[i].delta_time = 0L; x->track_chunk[i].track_index = 0L; x->track_chunk[i].total_time = 0L; x->track_chunk[i].running_status = 0; } x->total_time = 0L; x->ended = 0L; outlet_float(x->total_time_outlet, x->total_time); } static uint32_t midifile_get_next_track_chunk_delta_time(t_midifile *x, int mfTrack) /** return the delta_time of the next event in track[mfTrack] */ { unsigned char *cP, *last_cP; uint32_t delta_time; cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].track_index; last_cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].chunk_length; delta_time = NO_MORE_ELEMENTS; if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[mfTrack].delta_time != NO_MORE_ELEMENTS)) cP = midifile_read_var_len(cP, &delta_time); return delta_time; } /** output a long MIDI message as a list of floats * first_byte is followed by len bytes at cP */ static void midifile_output_long_list (t_outlet *outlet, unsigned char *cP, uint32_t len, unsigned char first_byte) { uint32_t slen; unsigned int si; t_atom *slist; slen = (len+1L)*sizeof(t_atom); slist = getbytes (slen); if (slist == NULL) { pd_error (NULL, "midifile: no memory for long list"); return; } slist[0].a_type = A_FLOAT; slist[0].a_w.w_float = first_byte;//0xF0; for (si = 0; si < len; ++si) { slist[si+1].a_type = A_FLOAT; slist[si+1].a_w.w_float = cP[si]; } outlet_list(outlet, &s_list, len+1L, slist); freebytes(slist, slen); } /** parse entire track chunk and output it to the main window */ static void midifile_dump_track_chunk_data(t_midifile *x, int mfTrack) { unsigned char *cP, *last_cP, *str; uint32_t total_time, delta_time, len; unsigned long time_sig; unsigned char status, running_status = 0, c, d, nn, dd, cc, bb, mi, mcp, ch, hr, mn, se, fr, ff; char sf; unsigned short sn; unsigned char tt[3]; char *msgPtr; char msg[256]; cP = x->track_chunk[mfTrack].track_data; last_cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].chunk_length; total_time = 0L; post("midifile: Parsing track[%d]...", mfTrack); while ((cP != NULL) && (cP < last_cP) && (x->track_chunk[mfTrack].delta_time != NO_MORE_ELEMENTS)) { msgPtr = msg; cP = midifile_read_var_len(cP, &delta_time); status = *cP++; total_time += delta_time; msgPtr += sprintf (msgPtr, "tick %d delta %d status %02X ", total_time, delta_time, status); if ((status & 0xF0) == 0xF0) { switch (status) { case 0xF0: case 0xF7: cP = midifile_read_var_len(cP, &len);/* not a time but the same variable length format */ msgPtr += sprintf(msgPtr, "Sysex: %02X length %d ", status, len); cP += len; break; case 0xF3: /* song select */ c = *cP++; msgPtr += sprintf(msgPtr, "Song Select: %d ", c); break; case 0xF2: /* song position */ c = *cP++; d = *cP++; msgPtr += sprintf(msgPtr, "Song Position %d ", midifile_combine_bytes(c, d)); break; case 0xF1: /* quarter frame */ msgPtr += sprintf(msgPtr, "MIDI Quarter Frame"); break; case 0xF6: /* tune request */ msgPtr += sprintf(msgPtr, "MIDI Tune Request"); break; case 0xF8: /* MIDI clock */ msgPtr += sprintf(msgPtr, "MIDI Clock"); break; case 0xF9: /* MIDI tick */ msgPtr += sprintf(msgPtr, "MIDI Tick"); break; case 0xFA: /* MIDI start */ msgPtr += sprintf(msgPtr, "MIDI Start"); break; case 0xFB: /* MIDI continue */ msgPtr += sprintf(msgPtr, "MIDI Continue"); break; case 0xFC: /* MIDI stop */ msgPtr += sprintf(msgPtr, "MIDI Stop"); break; case 0xFE: /* active sense */ msgPtr += sprintf(msgPtr, "MIDI Active Sense"); break; case 0xFF: c = *cP++; cP = midifile_read_var_len(cP, &len);/* not a time but the same variable length format */ msgPtr += sprintf(msgPtr, "Meta 0x%02X length %d \n", c, len); switch (c) { case 0x58: nn = *cP++; dd = *cP++; dd = 1<<(dd); cc = *cP++; bb = *cP++; msgPtr += sprintf( msgPtr, "Time Signature: %d/%d %d clocks per tick, %d 32nd notes per quarter note", nn, dd, cc, bb); break; case 0x59: sf = *(signed char*)cP++; mi = *cP++; msgPtr += sprintf( msgPtr, "Key Signature: %d %s, %s", (sf < 0)?-sf:sf, (sf<0)?"flats":"sharps", (mi)?"minor":"major"); break; case 0x54: hr = *cP++; mn = *cP++; se = *cP++; fr = *cP++; ff = *cP++; msgPtr += sprintf( msgPtr, "SMPTE Offset: %02d:%02d:%02d:%02d.%02d", hr&0x1F, mn, se, fr, ff); break; case 0x51: tt[0] = *cP++; tt[1] = *cP++; tt[2] = *cP++; time_sig = midifile_get_multibyte_3(tt); msgPtr += sprintf(msgPtr, "%lu microseconds per MIDI quarter-note", time_sig); break; case 0x2F: msgPtr += sprintf(msgPtr, "========End of Track %d==========", mfTrack); cP += len; break; case 0x21: tt[0] = *cP++; msgPtr += sprintf(msgPtr, "MIDI port or cable number (unofficial): %d", tt[0]); break; case 0x20: mcp = *cP++; msgPtr += sprintf(msgPtr, "MIDI Channel Prefix: %d", mcp); break; case 0x07: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Cue Point: %s", str); cP[len] = c; cP += len; break; case 0x06: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Marker: %s", str); cP[len] = c; cP += len; break; case 0x05: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Lyric: %s", str); cP[len] = c; cP += len; break; case 0x04: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Instrument Name: %s", str); cP[len] = c; cP += len; break; case 0x03: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Sequence/Track Name: %s", str); cP[len] = c; cP += len; break; case 0x02: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Copyright Notice: %s", str); cP[len] = c; cP += len; break; case 0x01: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Text: %s", str); cP[len] = c; cP += len; break; case 0x00: tt[0] = *cP++; tt[1] = *cP++; sn = midifile_get_multibyte_2(tt); msgPtr += sprintf(msgPtr, "Sequence Number: %d", sn); break; default: msgPtr += sprintf(msgPtr, "Unknown: 0x%02X", c); cP += len; break; } break; default: /* 0xF4, 0xF5, 0xF9, 0xFD are not defined */ msgPtr += sprintf(msgPtr, "Undefined: 0x%02X", status); break; } } else { if (status & 0x80) { running_status = status; c = *cP++; } else { c = status; status = running_status; } ch = (status & 0x0F) + 1; /* MIDI channel number */ switch (status & 0xF0) { case 0x80: d = *cP++; /* 2 data bytes */ msgPtr += sprintf(msgPtr, "MIDI 0x%02X %02X %02X : channel %d Note %d Off velocity %d", status, c, d, ch, c, d); break; case 0x90: d = *cP++; /* 2 data bytes */ if (d == 0) msgPtr += sprintf(msgPtr,"MIDI 0x%02X %02X %02X : channel %d Note %d Off", status, c, d, ch, c); else msgPtr += sprintf(msgPtr, "MIDI 0x%02X %02X %02X : channel %d Note %d On velocity %d", status, c, d, ch, c, d); break; case 0xA0: d = *cP++; /* 2 data bytes */ msgPtr += sprintf(msgPtr, "MIDI: 0x%02X %02X %02X : channel %d Note %d Aftertouch %d", status, c, d, ch, c, d); break; case 0xB0: d = *cP++; /* 2 data bytes */ msgPtr += sprintf(msgPtr, "MIDI: 0x%02X %02X %02X : channel %d Controller %d: %d", status, c, d, ch, c, d); break; case 0xC0: /* 1 data byte */ msgPtr += sprintf(msgPtr,"MIDI: 0x%02X %02X: channel %d Program Change: %d", status, c, ch, c); break; case 0xD0: /* 1 data byte */ msgPtr += sprintf(msgPtr,"MIDI: 0x%02X %02X: channel %d Channel Pressure: %d", status, c, ch, c); break; case 0xE0: /* 2 data bytes */ d = *cP++; /* 2 data bytes */ msgPtr += sprintf(msgPtr, "MIDI: 0x%02X %02X %02X : channel %d Pitch Wheel %d", status, c, d, ch, midifile_combine_bytes(c, d)); break; } } post("midifile: %s", msg); } } static void midifile_get_next_track_chunk_data(t_midifile *x, int mfTrack) /** parse the next track chunk data element and output via the appropriate outlet or post to main window * Sets the delta_time of the element or NO_MORE_ELEMENTS if no more elements */ { unsigned char *cP, *last_cP, *str; uint32_t delta_time, time_sig, len; unsigned char status, c, d=0, nn, dd, cc, bb, mi, mcp, n=0; char sf; char fps, hour, min, sec, frame, subframe; unsigned short sn; unsigned char tt[3]; t_atom output_atom[6]; cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].track_index; last_cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].chunk_length; delta_time = NO_MORE_ELEMENTS; if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[mfTrack].delta_time != NO_MORE_ELEMENTS)) { cP = midifile_read_var_len(cP, &delta_time); status = *cP++; if ((status & 0xF0) == 0xF0) { switch (status) { /* system message */ case 0xF0: case 0xF7: cP = midifile_read_var_len(cP, &len); /* packet length */ if (x->verbosity) post("midifile: Sysex: %02X length %d", status, len); midifile_output_long_list(x->midi_list_outlet, cP, len, 0xF0); cP += len; x->track_chunk[mfTrack].running_status = 0; break; case 0xF1: /* quarter frame */ x->midi_data[0].a_w.w_float = status; outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); x->track_chunk[mfTrack].running_status = 0; break; case 0xF3: /* song select */ c = *cP++; x->midi_data[0].a_w.w_float = status; x->midi_data[1].a_w.w_float = c; outlet_list(x->midi_list_outlet, &s_list, 2, x->midi_data); x->track_chunk[mfTrack].running_status = 0; break; case 0xF2: /* song position */ c = *cP++; x->midi_data[0].a_w.w_float = status; x->midi_data[1].a_w.w_float = c; c = *cP++; x->midi_data[2].a_w.w_float = c; outlet_list(x->midi_list_outlet, &s_list, 3, x->midi_data); x->track_chunk[mfTrack].running_status = 0; break; case 0xF6: /* tune request */ x->midi_data[0].a_w.w_float = status; outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); x->track_chunk[mfTrack].running_status = 0; break; case 0xF8: /* MIDI clock */ case 0xF9: /* MIDI tick */ case 0xFA: /* MIDI start */ case 0xFB: /* MIDI continue */ case 0xFC: /* MIDI stop */ case 0xFE: /* active sense */ x->midi_data[0].a_w.w_float = status; outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); break; case 0xFF: /* meta event */ c = *cP++; cP = midifile_read_var_len(cP, &len);/* meta length */ if (x->verbosity) post("midifile: Track %d Meta: %02X length %d", mfTrack, c, len); switch (c) { case 0x59: /* key signature */ sf = *(signed char *)cP++; mi = *cP++; if (x->verbosity) post ("midifile: Key Signature: %d %s, %s", sf, (sf<0)?"flats":"sharps", (mi)?"minor":"major"); SETFLOAT(&output_atom[0], sf); SETFLOAT(&output_atom[1], mi); SETSYMBOL(&output_atom[2], midifile_key_name(sf, mi)); outlet_anything( x->status_outlet, gensym("key_sig"), 3, output_atom); break; case 0x58: /* time signature */ nn = *cP++; dd = *cP++; dd = 1<<(dd); cc = *cP++; bb = *cP++; if (x->verbosity) post ("midifile: Time Signature: %d/%d %d clocks per tick, %d 32nd notes per quarternote", nn, dd, cc, bb); SETFLOAT(&output_atom[0], nn); SETFLOAT(&output_atom[1], dd); SETFLOAT(&output_atom[2], cc); SETFLOAT(&output_atom[3], bb); outlet_anything( x->status_outlet, gensym("time_sig"), 4, output_atom); break; case 0x54: /* smpte offset */ hour = *cP++; /* hour is mixed with fps as 0ffhhhhhh */ switch (hour>>6) { case 0: fps = 24; break; case 1: fps = 25; break; case 2: fps = 29;/* 30 fps dropframe */ break; case 3: fps = 30; break; default: fps = 0; /* error */ } hour = hour & 0x3F; min = *cP++; sec = *cP++; frame = *cP++; subframe = *cP++; if (x->verbosity) post ("midifile: SMPTE offset: %d:%d:%d:%d:%d, %d fps", hour, min, sec, frame, subframe, fps); SETFLOAT(&output_atom[0], hour); SETFLOAT(&output_atom[1], min); SETFLOAT(&output_atom[2], sec); SETFLOAT(&output_atom[3], frame); SETFLOAT(&output_atom[4], subframe); SETFLOAT(&output_atom[5], fps); outlet_anything( x->status_outlet, gensym("smpte"), 6, output_atom); break; case 0x51: /* set tempo */ tt[0] = *cP++; tt[1] = *cP++; tt[2] = *cP++; time_sig = (uint32_t)midifile_get_multibyte_3(tt); if (x->verbosity) post ("midifile: %lu microseconds per MIDI quarter-note", time_sig); SETFLOAT(&output_atom[0], time_sig); outlet_anything( x->status_outlet, gensym("microsec_per_quarternote"), 1, output_atom); break; case 0x2F: /* end of track */ if (x->verbosity) post ("midifile: End of Track %d", mfTrack); delta_time = NO_MORE_ELEMENTS; SETFLOAT(&output_atom[0], mfTrack); SETFLOAT(&output_atom[1], x->total_time); outlet_anything( x->status_outlet, gensym("end"), 2, output_atom); cP += len; break; case 0x21: tt[0] = *cP++; if (x->verbosity) post ("midifile: MIDI port or cable number (unofficial): %d", tt[0]); break; case 0x20: /* MIDI channel prefix */ mcp = *cP++; if (x->verbosity) post ("midifile: MIDI Channel Prefix: %d", mcp); SETFLOAT(&output_atom[0], mfTrack); SETFLOAT(&output_atom[1], mcp); outlet_anything( x->status_outlet, gensym("channel"), 2, output_atom); break; case 0x07: /* cue point */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Cue Point: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("cue"), 1, output_atom); cP[len] = c; cP += len; break; case 0x06: /* marker */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Marker: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("marker"), 1, output_atom); cP[len] = c; cP += len; break; case 0x05: /* lyrics */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Lyric: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("lyrics"), 1, output_atom); cP[len] = c; cP += len; break; case 0x04: /* instrument name */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Instrument Name: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("instr_name"), 1, output_atom); cP[len] = c; cP += len; break; case 0x03: /* sequence/track name */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Sequence/Track Name: %s", str); SETFLOAT(&output_atom[0], mfTrack); SETSYMBOL(&output_atom[1], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("name"), 2, output_atom); cP[len] = c; cP += len; break; case 0x02:/* copyright notice */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Copyright Notice: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("copyright"), 1, output_atom); cP[len] = c; cP += len; break; case 0x01: /* text event */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Text Event: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("text"), 1, output_atom); cP[len] = c; cP += len; break; case 0x00: /* sequence number */ tt[0] = *cP++; tt[1] = *cP++; sn = midifile_get_multibyte_2(tt); if (x->verbosity) post ("midifile: Sequence Number %d", sn); SETFLOAT(&output_atom[0], sn); outlet_anything( x->status_outlet, gensym("seq_num"), 1, output_atom); break; default: if (x->verbosity) post ("midifile: Unknown: %02X", c); cP += len; break; } break; default: /* 0xF4, 0xF5, 0xF9, 0xFD are not defined */ break; } } else { if (status & 0x80) { x->track_chunk[mfTrack].running_status = status;/* status is true status */ c = *cP++; } else { c = status; /* status is actually 1st data byte */ status = x->track_chunk[mfTrack].running_status; /* current status */ } switch (status & 0xF0) { case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0: n = 3; d = *cP++; /* 2 data bytes */ break; case 0xC0: /* 1 data byte */ case 0xD0: n = 2; break; } x->midi_data[0].a_w.w_float = status; x->midi_data[1].a_w.w_float = c; x->midi_data[2].a_w.w_float = (n == 3)?d:0; if (x->midi_data[0].a_w.w_float != 0) outlet_list(x->midi_list_outlet, &s_list, n, x->midi_data); if (x->track_chunk[mfTrack].running_status == 0) pd_error (x, "midifile: No running status on track %d at %d", mfTrack, x->track_chunk[mfTrack].total_time + delta_time); } } x->track_chunk[mfTrack].track_index = (uint32_t)((char *)cP - (char *)x->track_chunk[mfTrack].track_data); x->track_chunk[mfTrack].delta_time = delta_time; if (delta_time == NO_MORE_ELEMENTS) x->track_chunk[mfTrack].total_time = delta_time; else x->track_chunk[mfTrack].total_time += delta_time; } /** parse the next track chunk data element and skip it without any output * Sets the delta_time of the element or NO_MORE_ELEMENTS if no more elements */ static void midifile_skip_next_track_chunk_data(t_midifile *x, int mfTrack) { unsigned char *cP, *last_cP; uint32_t delta_time, len; unsigned char status, c, n; cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].track_index; last_cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].chunk_length; delta_time = NO_MORE_ELEMENTS; if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[mfTrack].delta_time != NO_MORE_ELEMENTS)) { cP = midifile_read_var_len(cP, &delta_time); status = *cP++; if ((status & 0xF0) == 0xF0) { switch (status) { /* system message */ case 0xF0: case 0xF7: cP = midifile_read_var_len(cP, &len); /* packet length */ cP += len; break; case 0xF1: /* quarter frame */ break; case 0xF3: /* song select */ cP += 1; break; case 0xF2: /* song position */ cP += 2; break; case 0xF6: /* tune request */ case 0xF8: /* MIDI clock */ case 0xF9: /* MIDI tick */ case 0xFA: /* MIDI start */ case 0xFB: /* MIDI continue */ case 0xFC: /* MIDI stop */ case 0xFE: /* active sense */ break; case 0xFF: c = *cP++; cP = midifile_read_var_len(cP, &len);/* meta length */ switch (c) { case 0x2F: if (x->verbosity) post ("midifile: End of Track %d", mfTrack); delta_time = NO_MORE_ELEMENTS; /* falls through */ default: cP += len; break; } break; default: /* 0xF4, 0xF5, 0xF9, 0xFD are not defined */ break; } } else { if (status & 0x80) { x->track_chunk[mfTrack].running_status = status; n = 1; } else { n = 0; /* no status in this message */ status = x->track_chunk[mfTrack].running_status; } switch (status & 0xF0) { case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0: n += 1; /* data bytes */ break; case 0xC0: case 0xD0: /* only one data byte */ break; } cP += n; } } x->track_chunk[mfTrack].track_index = (uint32_t)((char *)cP - (char *)x->track_chunk[mfTrack].track_data); x->track_chunk[mfTrack].delta_time = delta_time; if (delta_time == NO_MORE_ELEMENTS) x->track_chunk[mfTrack].total_time = delta_time; else x->track_chunk[mfTrack].total_time += delta_time; } /** set a symbol to the key name based on * sf= number of sharps if positive, else flats * mi = 0=major 1= minor */ static t_symbol *midifile_key_name(int sf, int mi) { char *maj_key[15]={"B", "Gb", "Db", "Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "Db"}; char *min_key[15]={"G#", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#", "G#", "D#", "Bb"}; char buf[8] = {"no_key."}; int i; if ((sf >= -7)&&(sf <= 7)) { if (mi == 1) { i = sprintf(buf, "%s", min_key[sf+7]); sprintf(buf+i, "%s", "Minor"); } else if (mi == 0) { i = sprintf(buf, "%s", maj_key[sf+7]); sprintf(buf+i, "%s", "Major"); } } return gensym(buf); } /* fin midifile.c */ midifile-0.4.2/pd-lib-builder/000077500000000000000000000000001471740550200160775ustar00rootroot00000000000000midifile-0.4.2/pd-lib-builder/CHANGELOG.txt000066400000000000000000000066431471740550200201400ustar00rootroot00000000000000Changelog for Makefile.pdlibbuilder. v0.6.0, dated 2019-12-21 - detect target platform (OS and architecture) rather than build platform (#55) - introduce optional user variable 'PLATFORM' for cross compilation - no longer build OSX/MacOS fat binaries by default (#21, #50) - do build fat binaries when 'extension=d_fat' is specified for OSX/MacOS - fix bug where minimum OSX/MacOS version wasn't defined, and set it to 10.6 v0.5.1, dated 2018-03-15 Fixes and improvements for Windows builds: - properly evaluate variables 'PDDIR' and 'PDBINDIR' to find pd.dll - define default path of 32 bit Pd on 64 bit Windows - link C++ externals with standard C libs on Windows, they don't load otherwise - strip installed Windows binaries by default (issues #34, #39, #41, #42 respectively) Warning for all platforms: variable 'PD_PATH' is no longer supported, use the equivalent 'PDDIR'. v0.5.0, dated 2018-01-23 Implement target architecture detection for Windows builds, and set appropriate options for 32 and 64 bit (used to be for 32 bit only). (feature, issue #37 #38, merge commit 215bf3e) v0.4.4, dated 2016-11-22 Use variable 'system' when evaluating 'for{Linux,Darwin,Windows}' (bugfix, issue #31, commit 2c14110) v0.4.3, dated 2016-11-02 Replace flags '-fpic' by 'fPIC'. (bugfix, issue #29, commit 426b38b) v0.4.2, dated 2016-10-30 Fix issue where incorrect message about m_pd.h is given. (bugfix, commit 2e13d8f) v0.4.1, dated 2016-10-27 Respect cflag for minimum OSX version when defined by lib makefile. (bugfix, pull request #22, commit 48c4127) v0.4.0, dated 2016-10-14 Introduced path variables PDDIR, PDINCLUDEDIR, PDBINDIR, PDLIBDIR which can also be defined in environment. (feature, issue #27, commit b0dab72) v0.3.1, dated 2016-10-13 Fix bug where pd.dll wouldn't be found. (bugfix, commit a0c87be) v0.3.0, dated 2016-10-09 Variable 'PD_PATH' introduced for pd-extended / pd-l2ork compatibility. (feature, issue #26, commit 41e9743) v0.2.8, dated 2016-10-09 Allow installed files to contain weird characters (notably '$'). (bugfix, pull request #20, commit 5b920b1) v0.2.7, dated 2016-10-04 Remove all default pd search paths except vanilla's. (discussion, issue #25, commit a6a89dc) v0.2.6, dated 2016-09-20 Redefined dependency checking so it won't stall rebuilds on OSX. (bugfix, issue #16, commit 9fd1795) v0.2.5, dated 2016-06-26 Fixed dependency checking for object files in other directories. (bugfix, commit f06e550) v0.2.4, dated 2016-06-25 Fixed regression bug that disabled all dependency checking. (bugfix, commit 1d7bb5e) v0.2.3, dated 2016-03-29 Disabled dependency checking for OSX <= 10.5 because it stalled rebuilds. (bugfix, issue #16, commit eb614fd) v0.2.2, dated 2016-03-28 Removed target 'pre' because it forced rebuild of everything in 'all'. (bugfix, issue #17, commit c989c8e) v0.2.1, dated 2015-12-27 Implement / respect 'CPPFLAGS','CFLAGS'and 'LDFLAGS'. (bugfix, issue #5, commit 98f3582) v0.2.0, dated 2015-12-19 Added per-platform multiline defines 'forLinux', 'forDarwin', 'forWindows'. (feature, pull request #9, commit 3946ea5) v0.1.0, dated 2015-12-08 Added targets 'pre' and 'post' to automatically run before and after 'all'. (feature, pull request #4, commit a5678ac) v0.0.2, dated 2015-12-06 Improved methods for searching pd paths. (bugfix, commit ed37e6b) v0.0.1, dated 2015-10-31 Fixed expansion of variable 'lib.version'. (bugfix, issue #1, commit 974b617) v0.0.0, dated 2015-06-24 Initial version. (commit 16517a2) midifile-0.4.2/pd-lib-builder/Makefile.pdlibbuilder000066400000000000000000001270261471740550200222070ustar00rootroot00000000000000# Makefile.pdlibbuilder dated 2019-12-21 version = 0.6.0 # Helper makefile for Pure Data external libraries. # Written by Katja Vetter March-June 2015 for the public domain. No warranties. # Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's # ShakeNMake. # # Grab the newest version of Makefile.pdlibbuilder from # https://github.com/pure-data/pd-lib-builder/ # # GNU make version >= 3.81 required. # # #=== characteristics =========================================================== # # # - defines build settings based on autodetected OS and architecture # - defines rules to build Pd class- or lib executables from C or C++ sources # - defines rules for libdir installation # - defines convenience targets for developer and user # - evaluates implicit dependencies for non-clean builds # # #=== basic usage =============================================================== # # # In your Makefile, define your Pd lib name and class files, and include # Makefile.pdlibbuilder at the end of the Makefile. Like so: # # ________________________________________________________________________ # # # Makefile for mylib # # lib.name = mylib # # class.sources = myclass1.c myclass2.c # # datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt # # include Makefile.pdlibbuilder # ________________________________________________________________________ # # # For files in class.sources it is assumed that class basename == source file # basename. The default target builds all classes as individual executables # with Pd's default extension for the platform. For anything more than the # most basic usage, continue reading. # # #=== list of Makefile.pdlibbuilder API variables =============================== # # # Variables available for definition in your library Makefile: # # - lib.name # - lib.setup.sources # - class.sources # - common.sources # - shared.sources # - .class.sources # - .class.ldflags # - .class.ldlibs # - cflags # - ldflags # - ldlibs # - datafiles # - datadirs # - makefiles # - makefiledirs # - externalsdir # # Optional multiline defines evaluated per operating system: # # - forLinux # - forDarwin # - forWindows # # Variables available for your makefile or make command line: # # - make-lib-executable # - suppress-wunused # # Path variables for make command line or environment: # # - PDDIR # - PDINCLUDEDIR # - PDBINDIR # - PDLIBDIR # # Standard make variables for make command line or environment: # # - CPPFLAGS # - CFLAGS # - LDFLAGS # - CC # - CXX # - INSTALL # - STRIP # - DESTDIR # # Optional user variables for make command line or environment: # # - PLATFORM # # Deprecated path variables: # # - pdincludepath # - pdbinpath # - objectsdir # # #=== descriptions of Makefile.pdlibbuilder API variables ======================= # # # lib.name: # Name of the library directory as it will be installed / distributed. Also the # name of the lib executable in the case where all classes are linked into # a single binary. # # lib.setup.sources: # Source file(s) (C or C++) which must be compiled only when linking all classes # into a single lib binary. # # class.sources: # All sources files (C or C++) for which the condition holds that # class name == source file basename. # # .class.sources: # Source file(s) (C or C++) specific to class . Use this for # multiple-source classes or when class name != source file basename. # # common.sources: # Source file(s) which must be statically linked to each class in the library. # # shared.sources: # Source file(s) (C or C++) to build a shared dynamic link lib, to be linked # with all class executables. # # cflags, ldflags, ldlibs: # Define cflags (preprocessor&compiler), ldflags (linker) and ldlibs (dynamic # link libs) for the whole library. These flags are added to platform-specific # flags defined by Makefile.pdlibbuilder. # # .class.ldflags and .class.ldlibs: # Define ldflags resp. ldlibs specific to class . These flags are # added to platform-specific flags defined by Makefile.pdlibbuilder, and flags # defined in your Makefile for the whole library. Note: cflags can not be # defined per class in the current implementation. # # datafiles and datadirs: # All extra files you want to include in binary distributions of the # library: abstractions and help patches, example patches, meta patch, readme # and license texts, manuals, sound files, etcetera. Use 'datafiles' for all # files that should go into your lib rootdir and 'datadirs' for complete # directories you want to copy from source to distribution. # # forLinux, forDarwin, forWindows: # Shorthand for 'variable definitions for Linux only' etc. Use like: # define forLinux # cflags += -DLINUX # class.sources += linuxthing.c # endef # # makefiles and makefiledirs: # Extra makefiles or directories with makefiles that should be made in sub-make # processes. # # make-lib-executable: # When this variable is defined 'yes' in your makefile or as command argument, # Makefile.pdlibbuilder will try to build all classes into a single library # executable (but it will force exit if lib.setup.sources is undefined). # If your makefile defines 'make-lib-executable=yes' as the library default, # this can still be overridden with 'make-lib-executable=no' as command argument # to build individual class executables (the Makefile.pdlibbuilder default.) # # suppress-wunused: # When this variable is defined ('yes' or any other value), -Wunused-variable, # -Wunused-parameter, -Wunused-value and -Wunused-function are suppressed, # but the other warnings from -Wall are retained. # # PDDIR: # Root directory of 'portable' pd package. When defined, PDINCLUDEDIR and # PDBINDIR will be evaluated as $(PDDIR)/src and $(PDDIR)/bin. # # PDINCLUDEDIR: # Directory where Pd API m_pd.h should be found, and other Pd header files. # Overrides the default search path. # # PDBINDIR: # Directory where pd.dll should be found for linking (Windows only). Overrides # the default search path. # # PDLIBDIR: # Root directory for installation of Pd library directories. Overrides the # default install location. # # DESTDIR: # Prepended path component for staged install. # # PLATFORM: # Target platform for cross compilation in the form of GNU triplet: # cpu-vendor-os. Example: x86_64-w64-mingw32. This specifies the tool chain that # pdlibbuilder will use, if installed and locatable. System and architecture # will then be autodefined accordingly. In most cases no other variables need to # be overridden. # # CPPFLAGS: # Preprocessor flags which are not strictly required for building. # # CFLAGS: # Compiler flags which are not strictly required for building. Compiler flags # defined by Makefile.pdlibbuilder for warning, optimization and architecture # specification are overriden by CFLAGS. # # LDFLAGS: # Linker flags which are not strictly required for building. Linker flags # defined by Makefile.pdlibbuilder for architecture specification are overriden # by LDFLAGS. # # CC and CXX: # C and C++ compiler programs as defined in your build environment. # # INSTALL # Definition of install program. # # STRIP # Name of strip program. Default 'strip' can be overridden in cross compilation # environments. # # objectsdir: # Root directory for installation of Pd library directories, like PDLIBDIR but # not overridable by environment. Supported for compatibility with pd-extended # central makefile, but deprecated otherwise. # # pdincludepath, pdbinpath: # As PDINCLUDEDIR and PDBINDIR but not overridable by environment. Deprecated # as user variables. # # #=== paths ===================================================================== # # # Source files in directories other than current working directory must be # prefixed with their relative path. Do not rely on VPATH or vpath. # Object (.o) files are built in the directory of their source files. # Executables are built in current working directory. # # Default search path for m_pd.h and other API header files is platform # dependent, and overridable by PDINCLUDEDIR: # # Linux: /usr/include/pd # # OSX: /Applications/Pd*.app/Contents/Resources/src # # Windows: %PROGRAMFILES%/Pd/src # %PROGRAMFILES(X86)%/Pd/src (32 bit builds on 64 bit Windows) # # Default search path for binary pd.dll (Windows), overridable by PDBINDIR # # %PROGRAMFILES%/Pd/bin # %PROGRAMFILES(X86)%/Pd/bin (32 bit builds on 64 bit Windows) # # Default location to install pd libraries is platform dependent, and # overridable by PDLIBDIR: # # Linux: /usr/local/lib/pd-externals # OSX: ~/Library/Pd # Windows: %APPDATA%/Pd # # https://puredata.info/docs/faq/how-do-i-install-externals-and-help-files # The rationale for not installing to ~/pd-externals by default on Linux # is that some people share the home dir between 32 and 64 bit installations. # # #=== targets =================================================================== # # # all: build $(executables) plus optional post target # post: target to build after $(executables) # alldebug: build all with -g option turned on for debug symbols # : force clean build of an individual class # .pre: make preprocessor output file in current working directory # .lst: make asm/source output file in current working directory # # install: install executables and data files # clean: remove build products from source tree # # help: print help text # vars: print makefile variables # allvars: print all variables # depend: print generated prerequisites # dumpmachine: print compiler output of option '-dumpmachine' # coffee: dummy target # # Variable $(executables) expands to class executables plus optional shared lib, # or alternatively to single lib executable when make-lib-executable=true. # Targets pre and post can be defined by library makefile. Make sure to include # Makefile.pdlibbuilder first so default target all will not be redefined. # # #=== Pd-extended libdir concept ================================================ # # # For libdir layout as conceived by Hans-Christoph Steiner, see: # # https://puredata.info/docs/developer/Libdir # # Files README.txt, LICENSE.txt and -meta.pd are part of the libdir # convention. Help patches for each class and abstraction are supposed to be # available. Makefile.pdlibbuilder does not force the presence of these files # however. It does not automatically include such files in libdir installations. # Data files you want to include in distributions must be defined explicitly in # your Makefile. # # #=== Makefile.pdlibbuilder syntax conventions ================================== # # # Makefile.pdlibbuilder variable names are lower case. Default make variables, # environment variables, and standard user variables (CC, CXX, CFLAGS, DESTDIR) # are upper case. Use target 'allvars' to print all variables and their values. # # 'Fields' in data variables are separated by dots, like in 'foo.class.sources'. # Words in variables expressing a function or command are separated by dashes, # like in 'make-lib-executable'. # # #=== useful make options ======================================================= # # # Use 'make -d ' to print debug details of the make process. # Use 'make -p ' to print make's database. # # #=== TODO ====================================================================== # # # - decide whether to use -static-libgcc or shared dll in MinGW # - cygwin support # - android support # - figure out how to handle '$' in filenames # - add makefile template targets dpkg-source dist libdir distclean tags? # # #=== end of documentation sections ============================================= # # ################################################################################ ################################################################################ ################################################################################ # GNU make version 3.81 (2006) or higher is required because of the following: # - function 'info' # - variable '.DEFAULT_GOAL' # force exit when make version is < 3.81 ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))), 3.81) $(error GNU make version 3.81 or higher is required) endif # Relative path to externals root dir in multi-lib source tree like # pd-extended SVN. Default is parent of current working directory. May be # defined differently in including makefile. externalsdir ?= .. # variable you can use to check if Makefile.pdlibbuilder is already included Makefile.pdlibbuilder = true ################################################################################ ### target platform detection ################################################## ################################################################################ #=== target platform =========================================================== # PLATFORM: optional user variable to define target platform for cross # compilation. Redefine build tools accordingly. PLATFORM should match # the exact target prefix of tools present in $PATH, like x86_64-w64-mingw32, # x86_64-apple-darwin12 etc. Tool definitions are exported to ensure submakes # will get the same. ifneq ($(PLATFORM),) ifneq ($(findstring darwin, $(PLATFORM)),) export CC = $(PLATFORM)-cc export CXX = $(PLATFORM)-c++ export CPP = $(PLATFORM)-cc else export CC = $(PLATFORM)-gcc export CXX = $(PLATFORM)-g++ export CPP = $(PLATFORM)-cpp endif STRIP = $(PLATFORM)-strip endif # Let (native or cross-) compiler report target triplet and isolate individual # words therein to facilitate later processing. target.triplet := $(subst -, ,$(shell $(CC) -dumpmachine)) #=== operating system ========================================================== # The following systems are defined: Linux, Darwin, Windows. GNU and # GNU/kFreeBSD are treated as Linux to get the same options. ifneq ($(filter linux gnu% kfreebsd, $(target.triplet)),) system = Linux endif ifneq ($(filter darwin%, $(target.triplet)),) system = Darwin endif ifneq ($(filter mingw% cygwin%, $(target.triplet)),) system = Windows endif # evaluate possible system-specific multiline defines from library makefile $(eval $(for$(system))) # TODO: Cygwin, Android #=== architecture ============================================================== # The following CPU names can be processed by pdlibbuilder: # i*86 Intel 32 bit # x86_64 Intel 64 bit # arm ARM 32 bit # aarch64 ARM 64 bit target.arch := $(firstword $(target.triplet)) ################################################################################ ### variables per platform ##################################################### ################################################################################ #=== flags per architecture ==================================================== # Set architecture-dependent cflags, mainly for Linux. For Mac and Windows, # arch.c.flags are overriden below. To see gcc's default architecture flags: # $ gcc -Q --help=target # ARMv6: Raspberry Pi 1st gen, not detectable from target.arch ifeq ($(shell uname), armv6l) arch.c.flags = -march=armv6 -mfpu=vfp -mfloat-abi=hard # ARMv7: Beagle, Udoo, RPi2 etc. else ifeq ($(target.arch), arm) arch.c.flags = -march=armv7-a -mfpu=vfpv3 -mfloat-abi=hard # ARMv8 64 bit, not tested yet else ifeq ($(target.arch), aarch64) arch.c.flags = -mcpu=cortex-a53 # Intel 32 bit, build with SSE and SSE2 instructions else ifneq ($(filter i%86, $(target.arch)),) arch.c.flags = -march=pentium4 -mfpmath=sse -msse -msse2 # Intel/AMD 64 bit, build with SSE, SSE2 and SSE3 instructions else ifeq ($(target.arch), x86_64) arch.c.flags = -march=core2 -mfpmath=sse -msse -msse2 -msse3 # if none of the above architectures detected else arch.c.flags = endif #=== flags and paths for Linux ================================================= ifeq ($(system), Linux) prefix = /usr/local libdir := $(prefix)/lib pkglibdir = $(libdir)/pd-externals pdincludepath := $(wildcard /usr/include/pd) extension = pd_linux cpp.flags := -DUNIX c.flags := -fPIC c.ldflags := -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags c.ldlibs := -lc -lm cxx.flags := -fPIC -fcheck-new cxx.ldflags := -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags cxx.ldlibs := -lc -lm -lstdc++ shared.extension = so shared.ldflags = -rdynamic -fPIC -shared -Wl,-soname,$(shared.lib) endif #=== flags and paths for Darwin ================================================ # LLVM-clang doesn't support -fcheck-new, therefore this flag is only used when # compiling with g++. ifeq ($(system), Darwin) pkglibdir = $(HOME)/Library/Pd pdincludepath := $(firstword $(wildcard \ /Applications/Pd*.app/Contents/Resources/src)) extension = pd_darwin cpp.flags := -DUNIX -DMACOSX -I /sw/include c.flags := c.ldflags := -undefined suppress -flat_namespace -bundle c.ldlibs := -lc cxx.ldflags := -undefined suppress -flat_namespace -bundle cxx.ldlibs := -lc shared.extension = dylib shared.ldflags = -dynamiclib -undefined dynamic_lookup \ -install_name @loader_path/$(shared.lib) \ -compatibility_version 1 -current_version 1.0 ifneq ($(filter %g++, $(CXX)),) cxx.flags := -fcheck-new endif ifeq ($(extension), d_fat) arch := i386 x86_64 else arch := $(target.arch) endif ifneq ($(filter -mmacosx-version-min=%, $(cflags)),) version.flag := $(filter -mmacosx-version-min=%, $(cflags)) else version.flag = -mmacosx-version-min=10.6 endif arch.c.flags := $(addprefix -arch , $(arch)) $(version.flag) arch.ld.flags := $(arch.c.flags) endif #=== flags and paths for Windows =============================================== # Standard paths on Windows contain spaces, and GNU make functions treat such # paths as lists, with unintended effects. Therefore we must use shell function # ls instead of make's wildcard when probing for a path, and use double quotes # when specifying a path in a command argument. # Default paths in Mingw / Mingw-w64 environments. 'PROGRAMFILES' is standard # location for builds with native architecture, 'ProgramFiles(x86)' for i686 # builds on x86_64 Windows (detection method by Lucas Cordiviola). Curly braces # required because of parentheses in variable name. ifeq ($(system), Windows) pkglibdir := $(APPDATA)/Pd ifeq ($(target.arch), i686) programfiles := ${ProgramFiles(x86)} else programfiles := $(PROGRAMFILES) endif pdbinpath := $(programfiles)/Pd/bin pdincludepath := $(programfiles)/Pd/src endif # Store default path to pd.dll in PDBINDIR if the latter is not user-defined. # For include path this is done in the platform-independent paths section below, # but for PDBINDIR it is done here so ld flags can be evaluated as immediate # variables. ifeq ($(system), Windows) ifdef PDDIR PDBINDIR := $(PDDIR)/bin endif PDBINDIR ?= $(pdbinpath) endif # TODO: decide whether -mms-bitfields should be specified. ifeq ($(system), Windows) cpp.flags := -DMSW -DNT ifeq ($(target.arch), i686) arch.c.flags := -march=pentium4 -msse -msse2 -mfpmath=sse else ifeq ($(target.arch), x86_64) cpp.flags := -DMSW -DNT -DPD_LONGINTTYPE=__int64 arch.c.flags := -march=core2 -msse -msse2 -msse3 -mfpmath=sse else arch.c.flags = endif extension = dll c.flags := c.ldflags := -static-libgcc -shared \ -Wl,--enable-auto-import "$(PDBINDIR)/pd.dll" c.ldlibs := cxx.flags := -fcheck-new cxx.ldflags := -static-libgcc -static-libstdc++ -shared \ -Wl,--enable-auto-import "$(PDBINDIR)/pd.dll" cxx.ldlibs := shared.extension = dll shared.ldflags := -static-libgcc -shared "$(PDBINDIR)/pd.dll" stripflags = --strip-all endif #=== paths ===================================================================== # Platform-dependent default paths are specified above, but overridable. # Path variables in upper case can be defined as make command argument or in the # environment. Variable 'objectsdir' is supported for compatibility with # the build system that pd-l2ork has inherited from pd-extended. PDINCLUDEDIR ?= $(pdincludepath) PDLIBDIR ?= $(firstword $(objectsdir) $(pkglibdir)) ifdef PDDIR PDINCLUDEDIR := $(wildcard $(PDDIR)/src) endif # base path where all components of the lib will be installed by default installpath := $(DESTDIR)$(PDLIBDIR)/$(lib.name) # check if include path contains spaces (as is often the case on Windows) # if so, store the path so we can later do checks with it pdincludepathwithspaces := $(if $(word 2, $(PDINCLUDEDIR)), $(PDINCLUDEDIR)) #=== accumulated build flags =================================================== # From GNU make docs: 'Users expect to be able to specify CFLAGS freely # themselves.' So we use CFLAGS to define options which are not strictly # required for compilation: optimizations, architecture specifications, and # warnings. CFLAGS can be safely overriden using a make command argument. # Variables cflags, ldflags and ldlibs may be defined in including makefile. optimization.flags = -O3 -ffast-math -funroll-loops -fomit-frame-pointer warn.flags = -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing # suppress -Wunused-variable & Co if you don't want to clutter a build log ifdef suppress-wunused warn.flags += $(addprefix -Wno-unused-, function parameter value variable) endif CFLAGS = $(warn.flags) $(optimization.flags) $(arch.c.flags) # preprocessor flags cpp.flags := -DPD -I "$(PDINCLUDEDIR)" $(cpp.flags) $(CPPFLAGS) # flags for dependency checking (cflags from makefile may define -I options) depcheck.flags := $(cpp.flags) $(cflags) # architecture specifications for linker are overridable by LDFLAGS LDFLAGS := $(arch.ld.flags) # now add the same ld flags to shared dynamic lib shared.ldflags += $(LDFLAGS) # accumulated flags for C compiler / linker c.flags := $(cpp.flags) $(c.flags) $(cflags) $(CFLAGS) c.ldflags := $(c.ldflags) $(ldflags) $(LDFLAGS) c.ldlibs := $(c.ldlibs) $(ldlibs) # accumulated flags for C++ compiler / linker cxx.flags := $(cpp.flags) $(cxx.flags) $(cflags) $(CFLAGS) cxx.ldflags := $(cxx.ldflags) $(ldflags) $(LDFLAGS) cxx.ldlibs := $(cxx.ldlibs) $(ldlibs) ################################################################################ ### variables: library name and version ######################################## ################################################################################ # strip possibles spaces from lib.name, they mess up calculated file names lib.name := $(strip $(lib.name)) # if meta file exists, check library version metafile := $(wildcard $(lib.name)-meta.pd) ifdef metafile lib.version := $(shell sed -n \ 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' \ $(metafile)) endif ################################################################################ ### variables: files ########################################################### ################################################################################ #=== sources =================================================================== # (re)define .class.sources using file names in class.sources define add-class-source $(notdir $(basename $v)).class.sources += $v endef $(foreach v, $(class.sources), $(eval $(add-class-source))) # derive class names from .class.sources variables sourcevariables := $(filter %.class.sources, $(.VARIABLES)) classes := $(basename $(basename $(sourcevariables))) # accumulate all source files specified in makefile classes.sources := $(sort $(foreach v, $(sourcevariables), $($v))) all.sources := $(classes.sources) $(lib.setup.sources) \ $(shared.sources) $(common.sources) #=== object files ============================================================== # construct object filenames from all C and C++ source file names classes.objects := $(addsuffix .o, $(basename $(classes.sources))) common.objects := $(addsuffix .o, $(basename $(common.sources))) shared.objects := $(addsuffix .o, $(basename $(shared.sources))) lib.setup.objects := $(addsuffix .o, $(basename $(lib.setup.sources))) all.objects = $(classes.objects) $(common.objects) $(shared.objects) \ $(lib.setup.objects) #=== executables =============================================================== # construct class executable names from class names classes.executables := $(addsuffix .$(extension), $(classes)) # Construct shared lib executable name if shared sources are defined. If # extension and shared extension are not identical, use both to facilitate co- # installation for different platforms, like .m_i386.dll and .m_amd64.dll. ifdef shared.sources ifeq ($(extension), $(shared.extension)) shared.lib = lib$(lib.name).$(shared.extension) else shared.lib = lib$(lib.name).$(extension).$(shared.extension) endif else shared.lib := endif ################################################################################ ### variables: tools ########################################################### ################################################################################ # aliases so we can later define 'compile-$1' and set 'c' or 'cxx' as argument compile-c := $(CC) compile-cxx := $(CXX) ################################################################################ ### checks ##################################################################### ################################################################################ # At this point most variables are defined. Now do some checks and info's # before rules begin. # print Makefile.pdlibbuilder version before possible termination $(info ++++ info: using Makefile.pdlibbuilder version $(version)) # Terminate if target triplet remained empty, to avoid all sorts of confusing # scenarios and spurious bugs. ifeq ($(target.triplet),) $(error Command "$(CC) -dumpmachine" did not return a target triplet, \ needed for a build. \ Is compiler "$(CC)" installed in your PATH? ($(PATH)). \ Does compiler "$(CC)" support option "-dumpmachine"?) endif # 'forward declaration' of default target, needed to do checks all: # To avoid unpredictable results, make sure the default target is not redefined # by including makefile. ifneq ($(.DEFAULT_GOAL), all) $(error Default target must be 'all'.) endif # find out which target(s) will be made ifdef MAKECMDGOALS goals := $(MAKECMDGOALS) else goals := all endif # store path to Pd API m_pd.h if it is found ifdef PDINCLUDEDIR mpdh := $(shell ls "$(PDINCLUDEDIR)/m_pd.h") endif # store path to pd.dll; if not found, ls will give a useful error ifeq ($(system), Windows) pddll := $(shell ls "$(PDBINDIR)/pd.dll") endif # when making target all, check if m_pd.h is found and print info about it ifeq ($(goals), all) $(if $(mpdh), \ $(info ++++ info: using Pd API $(mpdh)), \ $(warning Where is Pd API m_pd.h? Do 'make help' for info.)) endif # print target info $(info ++++ info: making target $(goals) $(if $(lib.name),in lib $(lib.name))) # when installing, print installpath info $(if $(filter install install-lib, $(goals)), $(info ++++ info: \ installpath is '$(installpath)')) #=== define executables ======================================================== # By default we build class executables, and optionally a shared dynamic link # lib. When make-lib-executable=yes we build all classes into a single lib # executable, on the condition that variable lib.setup.sources is defined. ifeq ($(make-lib-executable),yes) $(if $(lib.setup.sources), ,\ $(error Can not build library blob because lib.setup.sources is undefined)) executables := $(lib.name).$(extension) else executables := $(classes.executables) $(shared.lib) endif ################################################################################ ### rules: special targets ##################################################### ################################################################################ # Disable built-in rules. If some target can't be built with the specified # rules, it should not be built at all. MAKEFLAGS += --no-builtin-rules .PRECIOUS: .SUFFIXES: .PHONY: all post build-lib \ $(classes) $(makefiledirs) $(makefiles) \ install install-executables install-datafiles install-datadirs \ force clean vars allvars depend help ################################################################################ ### rules: build targets ####################################################### ################################################################################ # Target all forces the build of targets [$(executables) post] in # deterministic order. Target $(executables) builds class executables plus # optional shared lib or alternatively a single lib executable when # make-lib-executable=true. Target post is optionally defined by # library makefile. all: post post: $(executables) all: $(info ++++info: target all in lib $(lib.name) completed) # build all with -g option turned on for debug symbols alldebug: c.flags += -g alldebug: cxx.flags += -g alldebug: all #=== class executable ========================================================== # recipe for linking objects in class executable # argument $1 = compiler type (c or cxx) # argument $2 = class basename define link-class $(compile-$1) \ $($1.ldflags) $($2.class.ldflags) \ -o $2.$(extension) \ $(addsuffix .o, $(basename $($2.class.sources))) \ $(addsuffix .o, $(basename $(common.sources))) \ $($1.ldlibs) $($2.class.ldlibs) $(shared.lib) endef # general rule for linking object files in class executable %.$(extension): $(shared.lib) $(info ++++ info: linking objects in $@ for lib $(lib.name)) $(if $(filter %.cc %.cpp, $($*.class.sources)), \ $(call link-class,cxx,$*), \ $(call link-class,c,$*)) #=== library blob ============================================================== # build all classes into single executable build-lib: $(lib.name).$(extension) $(info ++++ info: library blob $(lib.name).$(extension) completed) # recipe for linking objects in lib executable # argument $1 = compiler type (c or cxx) define link-lib $(compile-$1) \ $($1.ldflags) $(lib.ldflags) \ -o $(lib.name).$(extension) $(all.objects) \ $($1.ldlibs) $(lib.ldlibs) endef # rule for linking objects in lib executable # declared conditionally to avoid name clashes ifeq ($(make-lib-executable),yes) $(lib.name).$(extension): $(all.objects) $(if $(filter %.cc %.cpp, $(all.sources)), \ $(call link-lib,cxx), \ $(call link-lib,c)) endif #=== shared dynamic lib ======================================================== # recipe for linking objects in shared executable # argument $1 = compiler type (c or cxx) define link-shared $(compile-$1) \ $(shared.ldflags) \ -o $(shared.lib) $(shared.objects) \ $($1.ldlibs) $(shared.ldlibs) endef # rule for linking objects in shared executable # build recipe is in macro 'link-shared' $(shared.lib): $(shared.objects) $(info ++++ info: linking objects in shared lib $@) $(if $(filter %.cc %.cpp, $(shared.sources)), \ $(call link-shared,cxx), \ $(call link-shared,c)) #=== object files ============================================================== # recipe to make .o file from source # argument $1 is compiler type (c or cxx) define make-object-file $(info ++++ info: making $@ in lib $(lib.name)) $(compile-$1) \ $($1.flags) \ -o $@ -c $< endef # Three rules to create .o files. These are double colon 'terminal' rules, # meaning they are the last in a rules chain. %.o:: %.c $(call make-object-file,c) %.o:: %.cc $(call make-object-file,cxx) %.o:: %.cpp $(call make-object-file,cxx) #=== explicit prerequisites for class executables ============================== # For class executables, prerequisite rules are declared in run time. Target # 'depend' prints these rules for debugging purposes. # declare explicit prerequisites rule like 'class: class.extension' # argument $v is class basename define declare-class-target $v: $v.$(extension) endef # declare explicit prerequisites rule like 'class.extension: object1.o object2.o' # argument $v is class basename define declare-class-executable-target $v.$(extension): $(addsuffix .o, $(basename $($v.class.sources))) \ $(addsuffix .o, $(basename $(common.sources))) endef # evaluate explicit prerequisite rules for all classes $(foreach v, $(classes), $(eval $(declare-class-target))) $(foreach v, $(classes), $(eval $(declare-class-executable-target))) #=== implicit prerequisites for class executables ============================== # Evaluating implicit prerequisites (header files) with help from the # preprocessor is 'expensive' so this is done conditionally and selectively. # Note that it is also possible to trigger a build via install targets, in # which case implicit prerequisites are not checked. # When the Pd include path contains spaces it will mess up the implicit # prerequisites rules. disable-dependency-tracking := $(strip $(pdincludepathwithspaces)) ifndef disable-dependency-tracking must-build-everything := $(filter all, $(goals)) must-build-class := $(filter $(classes), $(goals)) must-build-sources := $(foreach v, $(must-build-class), $($v.class.sources)) endif # declare implicit prerequisites rule like 'object.o: header1.h header2.h ...' # argument $1 is input source file(s) # dir is explicitly added because option -MM strips it by default define declare-object-target $(dir $1)$(filter %.o: %.h, $(shell $(CPP) $(depcheck.flags) -MM $1)) $(MAKEFILE_LIST) endef # evaluate implicit prerequisite rules when rebuilding everything ifdef must-build-everything $(if $(wildcard $(all.objects)), \ $(info ++++ info: evaluating implicit prerequisites in lib $(lib.name).....) \ $(foreach v, $(all.sources), $(eval $(call declare-object-target, $v)))) endif # evaluate implicit prerequisite rules when selectively building classes ifdef must-build-class $(foreach v, $(must-build-sources), \ $(eval $(call declare-object-target, $v))) $(foreach v, $(shared.sources), \ $(eval $(call declare-object-target, $v))) endif ################################################################################ ### rules: preprocessor and assembly files ##################################### ################################################################################ # Preprocessor and assembly output files for bug tracing etc. They are not part # of the build processes for executables. By default these files are created in # the current working directory. Dependency tracking is not performed, the build # is forced instead to make sure it's up to date. force: #=== preprocessor file ========================================================= # make preprocessor output file with extension .pre # argument $1 = compiler type (c or cxx) define make-preprocessor-file $(info ++++ info: making preprocessor output file $(notdir $*.pre) \ in current working directory) $(compile-$1) -E $< $(c.flags) $($1.flags) -o $(notdir $*.pre) endef %.pre:: %.c force $(call make-preprocessor-file,c) %.pre:: %.cc force $(call make-preprocessor-file,cxx) %.pre:: %.cpp force $(call make-preprocessor-file,cxx) #=== assembly file ============================================================= # make C / assembly interleaved output file with extension .lst # argument $1 = compiler type (c or cxx) define make-assembly-file $(info ++++ info: making assembly output file $(notdir $*.lst) \ in current working directory) $(compile-$1) \ -c -Wa,-a,-ad -fverbose-asm \ $($1.flags) \ $< > $(notdir $*.lst) endef %.lst:: %.c force $(call make-assembly-file,c) %.lst:: %.cc force $(call make-assembly-file,cxx) %.lst:: %.cpp force $(call make-assembly-file,cxx) ################################################################################ ### rules: installation targets ################################################ ################################################################################ #=== strip ===================================================================== # Stripping of installed binaries will only be done when variable 'stripflags' # is defined non-empty. No default definition is provided except for Windows # where the unstripped binaries are large, especially in the case of Mingw-w64. # Note: while stripping all symbols ('-s' or '--strip-all') is possible for # Linux and Windows, in the case of OSX only non-global symbols can be stripped # (option '-x' or '--discard-all'). # Make definition of strip command overridable so it can be defined in an # environment for cross-compilation. STRIP ?= strip # Commands in 'strip-executables' will be executed conditionally in the rule for # target 'install-executables'. strip-executables = cd "$(installpath)" && \ $(foreach v, $(executables), $(STRIP) $(stripflags) '$v';) #=== install =================================================================== # Install targets depend on successful exit status of target all because nothing # must be installed in case of a build error. # -p = preserve time stamps # -m = set permission mode (as in chmod) # -d = create all components of specified directories INSTALL = install INSTALL_PROGRAM := $(INSTALL) -p -m 644 INSTALL_DATA := $(INSTALL) -p -m 644 INSTALL_DIR := $(INSTALL) -m 755 -d # strip spaces from file names executables := $(strip $(executables)) datafiles := $(strip $(datafiles)) datadirs := $(strip $(datadirs)) # Do not make any install sub-target with empty variable definition because the # install program would exit with an error. install: $(if $(executables), install-executables) install: $(if $(datafiles), install-datafiles) install: $(if $(datadirs), install-datadirs) install-executables: all $(INSTALL_DIR) -v "$(installpath)" $(foreach v, $(executables), \ $(INSTALL_PROGRAM) '$v' "$(installpath)";) $(info ++++ info: executables of lib $(lib.name) installed \ from $(CURDIR) to $(installpath)) $(if $(stripflags), $(strip-executables),) install-datafiles: all $(INSTALL_DIR) -v "$(installpath)" $(foreach v, $(datafiles), \ $(INSTALL_DATA) '$(v)' "$(installpath)";) $(info ++++ info: data files of lib $(lib.name) installed \ from $(CURDIR) to $(installpath)) install-datadirs: all $(foreach v, $(datadirs), $(INSTALL_DIR) "$(installpath)/$v";) $(foreach v, $(datadirs), \ $(INSTALL_DATA) $(wildcard $v/*) "$(installpath)/$v";) $(info ++++ info: data directories of lib $(lib.name) installed \ from $(CURDIR) to $(installpath)) ################################################################################ ### rules: distribution targets ################################################ ################################################################################ # TODO # These targets are implemented in Makefile Template, but I have to figure out # how to do it under the not-so-strict conditions of Makefile.pdlibbuilder. # make source package dist: @echo "target dist not yet implemented" # make Debian source package dpkg-source: @echo "target dpkg-source not yet implemented" $(ORIGDIR): $(DISTDIR): ################################################################################ ### rules: clean targets ####################################################### ################################################################################ # delete build products from build tree clean: rm -f $(all.objects) rm -f $(classes.executables) $(lib.name).$(extension) $(shared.lib) rm -f *.pre *.lst # remove distribution directories and tarballs from build tree distclean: clean @echo "target distclean not yet implemented" ################################################################################ ### rules: submake targets ##################################################### ################################################################################ # Iterate over sub-makefiles or makefiles in other directories. # When 'continue-make=yes' is set, sub-makes will report 'true' to the parent # process regardless of their real exit status. This prevents the parent make # from being aborted by a sub-make error. Useful when you want to quickly find # out which sub-makes from a large set will succeed. ifeq ($(continue-make),yes) continue = || true endif # These targets will trigger sub-make processes for entries in 'makefiledirs' # and 'makefiles'. all alldebug install clean distclean dist dkpg-source: \ $(makefiledirs) $(makefiles) # this expands to identical rules for each entry in 'makefiledirs' $(makefiledirs): $(MAKE) --directory=$@ $(MAKECMDGOALS) $(continue) # this expands to identical rules for each entry in 'makefiles' $(makefiles): $(MAKE) --directory=$(dir $@) --makefile=$(notdir $@) $(MAKECMDGOALS) $(continue) ################################################################################ ### rules: convenience targets ################################################# ################################################################################ #=== show variables ============================================================ # Several 'function' macro's cause errors when expanded within a rule or without # proper arguments. Variables which are set with the define directive are only # shown by name for that reason. functions = \ add-class-source \ declare-class-target \ declare-class-executable-target \ declare-object-target \ link-class \ link-lib \ link-shared \ make-object-file \ make-preprocessor-file \ make-assembly-file # show variables from makefiles vars: $(info ++++ info: showing makefile variables:) $(foreach v,\ $(sort $(filter-out $(functions) functions, $(.VARIABLES))),\ $(if $(filter file, $(origin $v)),\ $(info variable $v = $($v)))) $(foreach v, $(functions), $(info 'function' name: $v)) @echo # show all variables allvars: $(info ++++ info: showing default, automatic and makefile variables:) $(foreach v, \ $(sort $(filter-out $(functions) functions, $(.VARIABLES))), \ $(info variable ($(origin $v)) $v = $($v))) $(foreach v, $(functions), $(info 'function' name: $v)) @echo #=== show dependencies ========================================================= # show generated prerequisites rules depend: $(info ++++ info: generated prerequisite rules) $(foreach v, $(classes), $(info $(declare-class-target))) $(foreach v, $(classes), $(info $(declare-class-executable-target))) $(foreach v, $(all.sources), $(info $(call declare-object-target, $v))) @echo #=== show help text ============================================================ # brief info about targets and paths ifdef mpdh mpdhinfo := $(mpdh) else mpdhinfo := m_pd.h was not found. Is Pd installed? endif help: @echo @echo " Main targets:" @echo " all: build executables (default target)" @echo " install: install all components of the library" @echo " vars: print makefile variables for troubleshooting" @echo " allvars: print all variables for troubleshooting" @echo " help: print this help text" @echo @echo " Pd API m_pd.h:" @echo " $(mpdhinfo)" @echo " You may specify your preferred Pd include directory as argument" @echo " to the make command, like 'PDINCLUDEDIR=path/to/pd/src'." @echo @echo " Path for installation of your libdir(s):" @echo " $(PDLIBDIR)" @echo " Alternatively you may specify your path for installation as argument" @echo " to the make command, like 'PDLIBDIR=path/to/pd-externals'." @echo @echo " Default paths are listed in the doc sections in Makefile.pdlibbuilder." @echo #=== platform test ============================================================= # This target can be used to test if the compiler for specified PLATFORM is # correctly defined and available. dumpmachine: @$(CC) -dumpmachine #=== dummy target ============================================================== coffee: @echo "Makefile.pdlibbuilder: Can not make coffee. Sorry." ################################################################################ ### end of rules sections ###################################################### ################################################################################ # for syntax highlighting in vim and github # vim: set filetype=make: midifile-0.4.2/pd-lib-builder/README.md000066400000000000000000000130711471740550200173600ustar00rootroot00000000000000 ### Makefile.pdlibbuilder ### Helper makefile for Pure Data external libraries. Written by Katja Vetter March-June 2015 for the public domain and since then developed as a Pd community project. No warranties. Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's ShakeNMake. GNU make version >= 3.81 required. ### characteristics ### * defines build settings based on autodetected target platform * defines rules to build Pd class- or lib executables from C or C++ sources * defines rules for libdir installation * defines convenience targets for developer and user * evaluates implicit dependencies for non-clean builds ### basic usage ### In your Makefile, define your Pd lib name and class files, and include Makefile.pdlibbuilder at the end of the Makefile. Like so: # Makefile for mylib lib.name = mylib class.sources = myclass1.c myclass2.c datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt include Makefile.pdlibbuilder For files in class.sources it is assumed that class name == source file basename. The default target builds all classes as individual executables with Pd's default extension for the platform. For anything more than the most basic usage, read the documentation sections in Makefile.pdlibbuilder. ### paths ### Makefile.pdlibbuilder >= v0.4.0 supports pd path variables which can be defined not only as make command argument but also in the environment, to override platform-dependent defaults: PDDIR: Root directory of 'portable' pd package. When defined, PDINCLUDEDIR and PDBINDIR will be evaluated as $(PDDIR)/src and $(PDDIR)/bin. PDINCLUDEDIR: Directory where Pd API m_pd.h should be found, and other Pd header files. Overrides the default search path. PDBINDIR: Directory where pd.dll should be found for linking (Windows only). Overrides the default search path. PDLIBDIR: Root directory for installation of Pd library directories. Overrides the default install location. ### platform detection and predefined variables ### Makefile.pdlibbuilder tries to detect architecture and operating system in order to define platform-specific variables. Since v0.6.0 we let the compiler report target platform, rather than taking the build machine as reference. This simplifies cross compilation. The kind of build options that are predefined: - optimizations useful for realtime DSP processing - options strictly required for the platform - options to make the build work accross a range of CPU's and OS versions The exact choice and definition predefined variables changes over time, as new platforms arrive and older platforms become obsolete. The easiest way to get an overview for your platform is by checking the flags categories in the output of target `vars`. Variables written in capitals (like `CFLAGS`) are intentionally exposed as user variables, although technically all makefile variables can be overridden by make command arguments. ### specific language versions ### Makefile.pdlibbuilder handles C and C++, but can not detect if your code uses features of a specific version (like C99, C++11, C++14 etc.). In such cases your makefile should specify that version as compiler option: cflags = -std=c++11 Also you may need to be explicit about minimum OSX version. For example, C++11 needs OSX 10.9 or higher: define forDarwin cflags = -mmacosx-version-min=10.9 endef ### documentation ### This README.md provides only basic information. A large comment section inside Makefile.pdlibbuilder lists and explains the available user variables, default paths, and targets. The internal documentation reflects the exact functionality of the particular version. For suggestions about project maintenance and advanced compilation see tips-tricks.md. ### versioning ### The project is versioned in MAJOR.MINOR.BUGFIX format (see http://semver.org), and maintained at https://github.com/pure-data/pd-lib-builder. Pd lib developers are invited to regulary check for updates, and to contribute and discuss improvements here. If you really need to distribute a personalized version with your library, rename Makefile.pdlibbuilder to avoid confusion. ### examples ### The list of projects using pd-lib-builder can be helpful if you are looking for examples, from the simplest use case to more complex implementations. - helloworld: traditional illustration of simplest use case - pd-windowing: straightforward real world use case of a small library - pd-nilwind / pd-cyclone: more elaborate source tree - zexy: migrated from autotools to pd-lib-builder ### projects using pd-lib-builder ### non-exhaustive list https://github.com/pure-data/helloworld https://github.com/electrickery/pd-nilwind https://github.com/electrickery/pd-maxlib https://github.com/electrickery/pd-sigpack https://github.com/electrickery/pd-tof https://github.com/electrickery/pd-windowing https://github.com/electrickery/pd-smlib https://github.com/porres/pd-cyclone https://github.com/porres/pd-else https://github.com/porres/pd-psycho https://git.iem.at/pd/comport https://git.iem.at/pd/hexloader https://git.iem.at/pd/iemgui https://git.iem.at/pd/iemguts https://git.iem.at/pd/iemlib https://git.iem.at/pd/iemnet https://git.iem.at/pd/iem_ambi https://git.iem.at/pd/iem_tab https://git.iem.at/pd/iem_adaptfilt https://git.iem.at/pd/iem_roomsim https://git.iem.at/pd/iem_spec2 https://git.iem.at/pd/mediasettings https://git.iem.at/pd/zexy https://git.iem.at/pd-gui/punish https://github.com/residuum/PuRestJson https://github.com/libpd/abl_link https://github.com/wbrent/timbreID https://github.com/MetaluNet/moonlib midifile-0.4.2/pd-lib-builder/tests/000077500000000000000000000000001471740550200172415ustar00rootroot00000000000000midifile-0.4.2/pd-lib-builder/tests/Makefile000066400000000000000000000005421471740550200207020ustar00rootroot00000000000000# recursively build all example projects in the subdirectories makefiledirs := $(filter-out _%, $(dir $(wildcard */Makefile))) PDLIBBUILDER_DIR = ../ include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder buildcheck installcheck: $(makefiledirs) runcheck: PDBINDIR=$(PDBINDIR) ./test-patches.sh $(makefiledirs:%=%*.pd) projects: @echo $(makefiledirs) midifile-0.4.2/pd-lib-builder/tests/_template_/000077500000000000000000000000001471740550200213525ustar00rootroot00000000000000midifile-0.4.2/pd-lib-builder/tests/_template_/Makefile000066400000000000000000000014231471740550200230120ustar00rootroot00000000000000# Makefile to build class '_template_' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = _template_ # input source file (class name == source file basename) class.sources = _template_.c # all extra files to be included in binary distribution of the library datafiles = _template_-help.pd _template_-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e _template_.$(extension) installcheck: install test -e $(installpath)/_template_.$(extension) midifile-0.4.2/pd-lib-builder/tests/_template_/_template_-help.pd000066400000000000000000000001361471740550200247360ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X obj 143 125 _template_; #X msg 143 93 7; #X connect 1 0 0 0; midifile-0.4.2/pd-lib-builder/tests/_template_/_template_-meta.pd000066400000000000000000000005211471740550200247320ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "_template_" external.; #X text 10 30 NAME _template_; #X restore 10 10 pd META; midifile-0.4.2/pd-lib-builder/tests/_template_/_template_.c000066400000000000000000000006631471740550200236340ustar00rootroot00000000000000#include t_class*_template__class; static void _template__float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*_template__new(void) { return pd_new(_template__class); } void _template__setup(void) { post("%s", __FUNCTION__); _template__class = class_new(gensym("_template_"), _template__new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(_template__class, _template__float); } midifile-0.4.2/pd-lib-builder/tests/make-from-template.sh000077500000000000000000000015741471740550200232760ustar00rootroot00000000000000#!/bin/sh template=_template_ template_dir=${0%/*}/${template} outdir=$1 outdir=${outdir%/} outname=${outdir##*/} usage() { cat 1>&2 < creates a new test-directory from _template_; must not exist yet. EOL if [ "x$@" != "x" ]; then echo echo " $@" 1>&2 fi exit 1 } if [ "x${outdir}" = "x" ]; then usage fi if [ -d "${outdir}" ]; then usage "output directory '${outdir}' already exists!" fi if [ ! -d "${template_dir}" ]; then echo "unable to find '${template_dir}'" 1>&2 exit 1 fi mkdir -p "${outdir}" || usage "unable to create '${outdir}'!" rmdir "${outdir}" cp -r "${template_dir}" "${outdir}" find "${outdir}" -type f -exec sed -e "s|${template}|${outname}|g" -i {} + for f in "${outdir}"/*; do g=$(echo $f | sed -e "s|${template}|${outname}|g") if [ "x${f}" != "x${g}" ]; then mv "${f}" "${g}" fi done midifile-0.4.2/pd-lib-builder/tests/multifor/000077500000000000000000000000001471740550200211025ustar00rootroot00000000000000midifile-0.4.2/pd-lib-builder/tests/multifor/Makefile000066400000000000000000000021411471740550200225400ustar00rootroot00000000000000# Makefile to build class 'multifor' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = multifor # input source file (class name == source file basename) class.sources = multiforA.c # additional classes define forLinux class.sources += multiforB.c endef define forDarwin class.sources += multiforB.c endef define forWindows class.sources += multiforB.c endef # all extra files to be included in binary distribution of the library datafiles = multifor-help.pd multifor-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e multiforA.$(extension) test -e multiforB.$(extension) installcheck: install test -e $(installpath)/multiforA.$(extension) test -e $(installpath)/multiforB.$(extension) test -e $(installpath)/multifor-help.pd test -e $(installpath)/multifor-meta.pd midifile-0.4.2/pd-lib-builder/tests/multifor/README.md000066400000000000000000000005251471740550200223630ustar00rootroot00000000000000multifor ======== minimal pd-lib-builder project that shows how to compile a library that contains multiple C-files that are compiled into multiple binaries each containing a different Pd-objectclass. some of the objectclasses are only compiled on specific platforms. this is a special case of the one-object-per-binary library structure. midifile-0.4.2/pd-lib-builder/tests/multifor/multifor-help.pd000066400000000000000000000002351471740550200242160ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X msg 143 93 7; #X obj 143 125 multiforA; #X obj 223 125 multiforB; #X msg 223 93 12; #X connect 0 0 1 0; #X connect 3 0 2 0; midifile-0.4.2/pd-lib-builder/tests/multifor/multifor-meta.pd000066400000000000000000000005151471740550200242150ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "multifor" external.; #X text 10 30 NAME multifor; #X restore 10 10 pd META; midifile-0.4.2/pd-lib-builder/tests/multifor/multiforA.c000066400000000000000000000006511471740550200232120ustar00rootroot00000000000000#include t_class*multiforA_class; static void multiforA_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multiforA_new(void) { return pd_new(multiforA_class); } void multiforA_setup(void) { post("%s", __FUNCTION__); multiforA_class = class_new(gensym("multiforA"), multiforA_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multiforA_class, multiforA_float); } midifile-0.4.2/pd-lib-builder/tests/multifor/multiforB.c000066400000000000000000000006511471740550200232130ustar00rootroot00000000000000#include t_class*multiforB_class; static void multiforB_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multiforB_new(void) { return pd_new(multiforB_class); } void multiforB_setup(void) { post("%s", __FUNCTION__); multiforB_class = class_new(gensym("multiforB"), multiforB_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multiforB_class, multiforB_float); } midifile-0.4.2/pd-lib-builder/tests/multilib/000077500000000000000000000000001471740550200210625ustar00rootroot00000000000000midifile-0.4.2/pd-lib-builder/tests/multilib/Makefile000066400000000000000000000017141471740550200225250ustar00rootroot00000000000000# Makefile to build class 'multilib' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = multilib make-lib-executable=yes # input source file (class name == source file basename) class.sources = multilibA.c multilibB.c # glue for building a multi-object library lib.setup.sources = $(lib.name).c # all extra files to be included in binary distribution of the library datafiles = multilib-help.pd multilib-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e multilib.$(extension) installcheck: install test -e $(installpath)/multilib.$(extension) test -e $(installpath)/multilib-help.pd test -e $(installpath)/multilib-meta.pd midifile-0.4.2/pd-lib-builder/tests/multilib/README.md000066400000000000000000000004061471740550200223410ustar00rootroot00000000000000multilib ======== minimal pd-lib-builder project that shows how to compile a library that contains multiple C-files that are compiled into a single binary containing different Pd-objectclasses. this is the general case of the single-binary library structure. midifile-0.4.2/pd-lib-builder/tests/multilib/multilib-help.pd000066400000000000000000000003341471740550200241560ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X declare -lib multilib; #X msg 143 93 7; #X obj 143 125 multilibA; #X obj 223 125 multilibB; #X msg 223 93 12; #X obj 136 47 declare -lib multilib; #X connect 0 0 1 0; #X connect 3 0 2 0; midifile-0.4.2/pd-lib-builder/tests/multilib/multilib-meta.pd000066400000000000000000000005151471740550200241550ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "multiple" external.; #X text 10 30 NAME multiple; #X restore 10 10 pd META; midifile-0.4.2/pd-lib-builder/tests/multilib/multilib.c000066400000000000000000000002021471740550200230410ustar00rootroot00000000000000 void multilibA_setup(void); void multilibB_setup(void); void multilib_setup(void) { multilibA_setup(); multilibB_setup(); } midifile-0.4.2/pd-lib-builder/tests/multilib/multilibA.c000066400000000000000000000006511471740550200231520ustar00rootroot00000000000000#include t_class*multilibA_class; static void multilibA_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multilibA_new(void) { return pd_new(multilibA_class); } void multilibA_setup(void) { post("%s", __FUNCTION__); multilibA_class = class_new(gensym("multilibA"), multilibA_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multilibA_class, multilibA_float); } midifile-0.4.2/pd-lib-builder/tests/multilib/multilibB.c000066400000000000000000000006511471740550200231530ustar00rootroot00000000000000#include t_class*multilibB_class; static void multilibB_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multilibB_new(void) { return pd_new(multilibB_class); } void multilibB_setup(void) { post("%s", __FUNCTION__); multilibB_class = class_new(gensym("multilibB"), multilibB_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multilibB_class, multilibB_float); } midifile-0.4.2/pd-lib-builder/tests/multiple/000077500000000000000000000000001471740550200210745ustar00rootroot00000000000000midifile-0.4.2/pd-lib-builder/tests/multiple/Makefile000066400000000000000000000016651471740550200225440ustar00rootroot00000000000000# Makefile to build class 'multiple' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = multiple # input source file (class name == source file basename) class.sources = multipleA.c multipleB.c # all extra files to be included in binary distribution of the library datafiles = multiple-help.pd multiple-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e multipleA.$(extension) test -e multipleB.$(extension) installcheck: install test -e $(installpath)/multipleA.$(extension) test -e $(installpath)/multipleB.$(extension) test -e $(installpath)/multiple-help.pd test -e $(installpath)/multiple-meta.pd midifile-0.4.2/pd-lib-builder/tests/multiple/README.md000066400000000000000000000004241471740550200223530ustar00rootroot00000000000000multiple ======== minimal pd-lib-builder project that shows how to compile a library that contains multiple C-files that are compiled into multiple binaries each containing a different Pd-objectclass. this is the general case of the one-object-per-binary library structure. midifile-0.4.2/pd-lib-builder/tests/multiple/multiple-help.pd000066400000000000000000000002351471740550200242020ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X msg 143 93 7; #X obj 143 125 multipleA; #X obj 223 125 multipleB; #X msg 223 93 12; #X connect 0 0 1 0; #X connect 3 0 2 0; midifile-0.4.2/pd-lib-builder/tests/multiple/multiple-meta.pd000066400000000000000000000005151471740550200242010ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "multiple" external.; #X text 10 30 NAME multiple; #X restore 10 10 pd META; midifile-0.4.2/pd-lib-builder/tests/multiple/multipleA.c000066400000000000000000000006511471740550200231760ustar00rootroot00000000000000#include t_class*multipleA_class; static void multipleA_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multipleA_new(void) { return pd_new(multipleA_class); } void multipleA_setup(void) { post("%s", __FUNCTION__); multipleA_class = class_new(gensym("multipleA"), multipleA_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multipleA_class, multipleA_float); } midifile-0.4.2/pd-lib-builder/tests/multiple/multipleB.c000066400000000000000000000006511471740550200231770ustar00rootroot00000000000000#include t_class*multipleB_class; static void multipleB_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multipleB_new(void) { return pd_new(multipleB_class); } void multipleB_setup(void) { post("%s", __FUNCTION__); multipleB_class = class_new(gensym("multipleB"), multipleB_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multipleB_class, multipleB_float); } midifile-0.4.2/pd-lib-builder/tests/multiplexx/000077500000000000000000000000001471740550200214545ustar00rootroot00000000000000midifile-0.4.2/pd-lib-builder/tests/multiplexx/Makefile000066400000000000000000000017171471740550200231220ustar00rootroot00000000000000# Makefile to build class 'multiplexx' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = multiplexx # input source file (class name == source file basename) class.sources = multiplexxA.cpp multiplexxB.c # all extra files to be included in binary distribution of the library datafiles = multiplexx-help.pd multiplexx-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e multiplexxA.$(extension) test -e multiplexxB.$(extension) installcheck: install test -e $(installpath)/multiplexxA.$(extension) test -e $(installpath)/multiplexxB.$(extension) test -e $(installpath)/multiplexx-help.pd test -e $(installpath)/multiplexx-meta.pd midifile-0.4.2/pd-lib-builder/tests/multiplexx/README.md000066400000000000000000000004321471740550200227320ustar00rootroot00000000000000multiplexx ======== minimal pd-lib-builder project that shows how to compile a library that contains multiplexx C-files that are compiled into multiplexx binaries each containing a different Pd-objectclass. this is the general case of the one-object-per-binary library structure. midifile-0.4.2/pd-lib-builder/tests/multiplexx/multiplexx-help.pd000066400000000000000000000002411471740550200251370ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X msg 143 93 7; #X obj 143 125 multiplexxA; #X obj 223 125 multiplexxB; #X msg 223 93 12; #X connect 0 0 1 0; #X connect 3 0 2 0; midifile-0.4.2/pd-lib-builder/tests/multiplexx/multiplexx-meta.pd000066400000000000000000000005211471740550200251360ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "multiplexx" external.; #X text 10 30 NAME multiplexx; #X restore 10 10 pd META; midifile-0.4.2/pd-lib-builder/tests/multiplexx/multiplexxA.cpp000066400000000000000000000011201471740550200244660ustar00rootroot00000000000000#include #include t_class*multiplexxA_class; static void multiplexxA_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multiplexxA_new(void) { return pd_new(multiplexxA_class); } #if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) extern "C" { void multiplexxA_setup(void); } #endif void multiplexxA_setup(void) { std::cerr << __FUNCTION__ << std::endl; multiplexxA_class = class_new(gensym("multiplexxA"), multiplexxA_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multiplexxA_class, multiplexxA_float); } midifile-0.4.2/pd-lib-builder/tests/multiplexx/multiplexxB.c000066400000000000000000000006751471740550200241450ustar00rootroot00000000000000#include t_class*multiplexxB_class; static void multiplexxB_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multiplexxB_new(void) { return pd_new(multiplexxB_class); } void multiplexxB_setup(void) { post("%s", __FUNCTION__); multiplexxB_class = class_new(gensym("multiplexxB"), multiplexxB_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multiplexxB_class, multiplexxB_float); } midifile-0.4.2/pd-lib-builder/tests/multishared/000077500000000000000000000000001471740550200215625ustar00rootroot00000000000000midifile-0.4.2/pd-lib-builder/tests/multishared/Makefile000066400000000000000000000025271471740550200232300ustar00rootroot00000000000000# Makefile to build class 'multishared' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = multishared # common functions shared.sources = shared.c # input source file (class name == source file basename) class.sources = multisharedA.c multisharedB.c # all extra files to be included in binary distribution of the library datafiles = multishared-help.pd multishared-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all ifeq ($(shared.extension), $(extension)) test -e lib$(lib.name).$(shared.extension) else test -e lib$(lib.name).$(extension).$(shared.extension) endif test -e multisharedA.$(extension) test -e multisharedB.$(extension) installcheck: install ifeq ($(shared.extension), $(extension)) test -e $(installpath)/lib$(lib.name).$(shared.extension) else test -e $(installpath)/lib$(lib.name).$(extension).$(shared.extension) endif test -e $(installpath)/multisharedA.$(extension) test -e $(installpath)/multisharedB.$(extension) test -e $(installpath)/multishared-help.pd test -e $(installpath)/multishared-meta.pd midifile-0.4.2/pd-lib-builder/tests/multishared/README.md000066400000000000000000000005201471740550200230360ustar00rootroot00000000000000multishared =========== minimal pd-lib-builder project that shows how to compile a library that contains multiple C-files that are compiled into multiple binaries each containing a different Pd-objectclass. a local shared library is used for common components. this is an extended case of the one-object-per-binary library structure. midifile-0.4.2/pd-lib-builder/tests/multishared/multishared-help.pd000066400000000000000000000002431471740550200253550ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X msg 143 93 7; #X obj 143 125 multisharedA; #X obj 223 125 multisharedB; #X msg 223 93 12; #X connect 0 0 1 0; #X connect 3 0 2 0; midifile-0.4.2/pd-lib-builder/tests/multishared/multishared-meta.pd000066400000000000000000000005231471740550200253540ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "multishared" external.; #X text 10 30 NAME multishared; #X restore 10 10 pd META; midifile-0.4.2/pd-lib-builder/tests/multishared/multishared.h000066400000000000000000000000641471740550200242540ustar00rootroot00000000000000#include void multishared_foo(t_float f); midifile-0.4.2/pd-lib-builder/tests/multishared/multisharedA.c000066400000000000000000000007451471740550200243560ustar00rootroot00000000000000#include "multishared.h" t_class*multisharedA_class; static void multisharedA_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); multishared_foo(f1); } static void*multisharedA_new(void) { return pd_new(multisharedA_class); } void multisharedA_setup(void) { post("%s", __FUNCTION__); multisharedA_class = class_new(gensym("multisharedA"), multisharedA_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multisharedA_class, multisharedA_float); } midifile-0.4.2/pd-lib-builder/tests/multishared/multisharedB.c000066400000000000000000000007451471740550200243570ustar00rootroot00000000000000#include "multishared.h" t_class*multisharedB_class; static void multisharedB_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); multishared_foo(f1); } static void*multisharedB_new(void) { return pd_new(multisharedB_class); } void multisharedB_setup(void) { post("%s", __FUNCTION__); multisharedB_class = class_new(gensym("multisharedB"), multisharedB_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multisharedB_class, multisharedB_float); } midifile-0.4.2/pd-lib-builder/tests/multishared/shared.c000066400000000000000000000001411471740550200231700ustar00rootroot00000000000000#include "multishared.h" void multishared_foo(t_float f) { post("%s(%f)", __FUNCTION__, f); } midifile-0.4.2/pd-lib-builder/tests/single/000077500000000000000000000000001471740550200205225ustar00rootroot00000000000000midifile-0.4.2/pd-lib-builder/tests/single/Makefile000066400000000000000000000013671471740550200221710ustar00rootroot00000000000000# Makefile to build class 'single' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = single # input source file (class name == source file basename) class.sources = single.c # all extra files to be included in binary distribution of the library datafiles = single-help.pd single-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e single.$(extension) installcheck: install test -e $(installpath)/single.$(extension) midifile-0.4.2/pd-lib-builder/tests/single/README.md000066400000000000000000000004051471740550200220000ustar00rootroot00000000000000single ====== minimal pd-lib-builder project that shows how to compile a library that contains a single C-file that is compiled into a single binary containing a single Pd-objectclass. this is a degenerate case of the one-object-per-binary library structure. midifile-0.4.2/pd-lib-builder/tests/single/single-help.pd000066400000000000000000000001321471740550200232520ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X obj 143 125 single; #X msg 143 93 7; #X connect 1 0 0 0; midifile-0.4.2/pd-lib-builder/tests/single/single-meta.pd000066400000000000000000000005111471740550200232510ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "single" external.; #X text 10 30 NAME single; #X restore 10 10 pd META; midifile-0.4.2/pd-lib-builder/tests/single/single.c000066400000000000000000000006131471740550200221470ustar00rootroot00000000000000#include t_class*single_class; static void single_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*single_new(void) { return pd_new(single_class); } void single_setup(void) { post("%s", __FUNCTION__); single_class = class_new(gensym("single"), single_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(single_class, single_float); } midifile-0.4.2/pd-lib-builder/tests/subdir/000077500000000000000000000000001471740550200205315ustar00rootroot00000000000000midifile-0.4.2/pd-lib-builder/tests/subdir/Makefile000066400000000000000000000015251471740550200221740ustar00rootroot00000000000000# Makefile to build class 'subdir' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = subdir # input source file (class name == source file basename) class.sources = src/subdir.c src/subdir~.c # all extra files to be included in binary distribution of the library datafiles = subdir-help.pd subdir-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e subdir.$(extension) test -e subdir~.$(extension) installcheck: install test -e $(installpath)/subdir.$(extension) test -e $(installpath)/subdir~.$(extension) midifile-0.4.2/pd-lib-builder/tests/subdir/README.md000066400000000000000000000004301471740550200220050ustar00rootroot00000000000000subdir ====== pd-lib-builder project that shows how to compile a library that contains a single C-file in a separate src/ directory, that is compiled into a single binary containing a subdir Pd-objectclass. this is a special case of the one-object-per-binary library structure. midifile-0.4.2/pd-lib-builder/tests/subdir/src/000077500000000000000000000000001471740550200213205ustar00rootroot00000000000000midifile-0.4.2/pd-lib-builder/tests/subdir/src/subdir.c000066400000000000000000000006131471740550200227540ustar00rootroot00000000000000#include t_class*subdir_class; static void subdir_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*subdir_new(void) { return pd_new(subdir_class); } void subdir_setup(void) { post("%s", __FUNCTION__); subdir_class = class_new(gensym("subdir"), subdir_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(subdir_class, subdir_float); } midifile-0.4.2/pd-lib-builder/tests/subdir/src/subdir~.c000066400000000000000000000007021471740550200231510ustar00rootroot00000000000000#include t_class*subdir_tilde_class; static void subdir_tilde_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*subdir_tilde_new(void) { return pd_new(subdir_tilde_class); } void subdir_tilde_setup(void) { post("%s", __FUNCTION__); subdir_tilde_class = class_new(gensym("subdir~"), subdir_tilde_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(subdir_tilde_class, subdir_tilde_float); } midifile-0.4.2/pd-lib-builder/tests/subdir/subdir-help.pd000066400000000000000000000001321471740550200232700ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X obj 143 125 subdir; #X msg 143 93 7; #X connect 1 0 0 0; midifile-0.4.2/pd-lib-builder/tests/subdir/subdir-meta.pd000066400000000000000000000005111471740550200232670ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "subdir" external.; #X text 10 30 NAME subdir; #X restore 10 10 pd META; midifile-0.4.2/pd-lib-builder/tests/subdir/subdir~-help.pd000066400000000000000000000001331471740550200234670ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X obj 143 125 subdir~; #X msg 143 93 7; #X connect 1 0 0 0; midifile-0.4.2/pd-lib-builder/tests/test-patches.sh000077500000000000000000000031141471740550200222030ustar00rootroot00000000000000#!/bin/sh ## simple script to open patches via Pd, and check for errors ## - each patch is opened separately ## - if an error is encountered, the Pd-printout is displayed ## (else it is suppressed) ## - if any of the patches encountered an error, the script will ## exit with a non-0 code if [ "x${PD}" = "x" ]; then if [ "x${PDBINDIR}" != "x" ]; then for exe in pd.com pd pd.exe; do if [ -x "${PDBINDIR}/${exe}" ]; then PD="${PDBINDIR}/${exe}" break fi done if [ "x${PD}" = "x" ]; then echo "WARNING: couldn't find a usable Pd in '${PDBINDIR}'" 1>&2 fi fi fi if [ "x${PD}" = "x" ]; then PD=pd fi echo "using Pd: ${PD}" failed=0 failed_tests="" succeeded=0 open1patch() { logfile=$(mktemp) local patch=$1 local patchdir=${patch%%/*} local patchfile=${patch#*/} patchfile=${patchfile#/} #echo "INFO: running ${patchfile} in ${patchdir}" cd "${patchdir}" && \ ${PD} -batch -nrt -noprefs -nostdpath -open "${patchfile}" -send "pd quit" \ >"${logfile}" 2>&1 ret=$? if grep "error: ... couldn't create" "${logfile}" >/dev/null; then ret=1 fi if [ "x${ret}" != "x0" ]; then echo "" cat "${logfile}" echo "FAILED[$ret]: ${patch}" else echo "SUCCEEDED: ${patch}" fi rm "${logfile}" return $ret } for p in "${@}"; do if (open1patch "${p}"); then succeeded=$((succeeded+1)) else failed=$((failed+1)) failed_tests="${failed_tests} ${p}" fi done echo "" echo "SUCCESS: ${succeeded}" echo "FAILURE: ${failed}" test ${failed} -eq 0 || echo "FAILS :${failed_tests}" test ${failed} -eq 0 midifile-0.4.2/pd-lib-builder/tips-tricks.md000066400000000000000000000164001471740550200206760ustar00rootroot00000000000000pd-lib-builder cheatsheet ========================= # Creating special builds ## building for non-native platform Using pd-lib-builder >=0.6.0 we can define variable `PLATFORM` to specify a target triplet for cross-compilation. Assuming a W32 package for Pd is unzipped into path `${PDWIN32}`, to build for Windows 32 bit: make PLATFORM=i686-w64-mingw32 PDDIR="${PDWIN32}" #### older pd-lib-builder versions Using pd-lib-builder < 0.6.0, in the absence of variable `PLATFORM`, you would instead override variables `system`, `target.arch`, `CC` and / or `CXX`, `STRIP`. Example: make system=Windows target.arch=i686 CC=i686-w64-mingw32-gcc STRIP=i686-w64-mingw32-strip PDDIR="${PDWIN32}" #### toolchains To build for non-native OS and/or architecture you need a cross toolchain. On Linux such toolchains are relatively easy to get. For example Debian Buster amd64 provides them for the following platforms (install g++ with dependencies for a given platform to get the whole toolchain): - `arm-linux-gnueabihf` - `aarch64-linux-gnu` - `i686-linux-gnu` - `i686-w64-mingw32` and `x86_64-w64-mingw32` (install `mingw-w64`) Cross toolchains for OSX/MacOS are not generally distributed. Project `osxcross` from Thomas Poechtraeger can create them for Linux. ## building double-precision externals At the time of writing (2018-02) there is no official Pd that supports double-precision numbers yet. However, if you do get hold of an experimental double-precision Pd, you can easily build your externals for 64-bit numbers: make CPPFLAGS="-DPD_FLOATSIZE=64" ## building externals for W64 (64-bit Windows) At the time of writing (2018-02) there is no official Pd that supports W64 yet. However, if you do get hold of an experimental W64 Pd, you can easily build your externals for this environment with make CPPFLAGS="-DPD_LONGINTTYPE=__int64" CC=x86_64-w64-mingw32-gcc To build a double-precision external for W64, use something like: make CPPFLAGS="-DPD_LONGINTTYPE=__int64 -DPD_FLOATSIZE=64" CC=x86_64-w64-mingw32-gcc ## TODO universal binaries on OSX # Project management In general it is advised to put the `Makefile.pdlibbuilder` into a separate subdirectory (e.g. `pd-lib-builder/`). This makes it much easier to update the `Makefile.pdlibbuilder` later You *should* also use a variable to the actual path of the Makefile.pdlibbuilder (even if you keep it in the root-directory), as this allows easy experimenting with newer (or older) (or site-specific) versions of the pd-lib-builder Makefile. ~~~make PDLIBBUILDER_DIR=pd-lib-builder/ include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder ~~~ ## Keeping pd-lib-builder up-to-date ### `git subtree` With git-subtrees, you make the pd-lib-builder repository (or any other repository for that matter) part of your own repository - with full history and everything - put nicely into a distinct subdirectory. Support for *manipulating* subtrees has been added with Git-v1.7.11 (May 2012). The nice thing however is, that from "outside" the subtree is part of your repository like any other directory. E.g. older versions of Git can clone your repository with the full subtree (and all it's history) just fine. You can also use git-archive to make a complete snapshot of your repository (including the subtree) - nice, if you e.g. want self-contained downloads of your project from git hosting platforms (like Github, Gitlab, Bitbucket,...) In short, `git subtree` is the better `git submodule`. So here's how to do it: #### Initial setup/check-out This will create a `pd-lib-builder/` directory containing the full history of the pd-lib-builder repository up to its release `v0.5.0` ~~~sh git subtree add --prefix=pd-lib-builder/ https://github.com/pure-data/pd-lib-builder v0.5.0 ~~~ This will automatically merge the `pd-lib-builder/` history into your current branch, so everything is ready to go. #### Cloning your repository with the subtree Nothing special, really. Just clone your repository as always: ~~~sh git clone https://git.example.org/pd/superbonk~.git ~~~ #### Updating the subtree Time passes and sooner or later you will find, that there is a shiny new pd-lib-builder with plenty of bugfixes and new features. To update your local copy to pd-lib-builder's current `master`, simply run: ~~~sh git subtree pull --prefix pd-lib-builder/ https://github.com/pure-data/pd-lib-builder master ~~~ #### Pulling the updated subtree into existing clones Again, nothing special. Just pull as always: ~~~sh git pull ~~~ #### Further reading More on the power of `git subtree` can be found online - https://medium.com/@v/git-subtrees-a-tutorial-6ff568381844 - https://www.atlassian.com/blog/git/alternatives-to-git-submodule-git-subtree - ... ### ~~`git submodule`~~ [DISCOURAGED] #### Initial setup/check-out To add a new submodule to your repository, just run `git submodule add` and commit the changes: ~~~sh git submodule add https://github.com/pure-data/pd-lib-builder git commit .gitmodules pd-lib-builder/ -m "Added pd-lib-builder as git-submodule" ~~~ #### Cloning your repository with the submodule When doing a fresh clone of your repository, pass the `--recursive` option to automatically fetch all submodules: ~~~sh git clone --recursive https://git.example.org/pd/superbonk~.git ~~~ If you've cloned non-recursively, you can initialize and update the submodules manually: ~~~sh git submodule init git submodule update ~~~ #### Updating the submodule Submodules are usually fixed to a given commit in their repository. To update the `pd-lib-builder` submodule to the current `master` do something like: ~~~sh cd pd-lib-builder git checkout master git pull cd .. git status pd-lib-builder git commit pd-lib-builder -m "Updated pd-lib-builder to current master" ~~~ #### Pulling the updated submodule into existing clones After you have pushed the submodule updates in your repository, other clones of the repository can be updated as follows: ~~~sh git pull ~~~ The above will make your repository aware, that the submodule is out-of-sync. ~~~sh $ LANG=C git status pd-lib-builder On branch master Your branch is up to date with 'origin/master'. Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) modified: pd-lib-builder (new commits) $ ~~~ In order to sync the submodule to the correct commit, run the following: ~~~sh git submodule update ~~~ #### Drawbacks `git submodule` has a number of drawbacks: - it requires special commands to synchronize the submodules, in addition to synching your repository. - you must make sure to use an URL for the submodule that is accessible to your potential users. e.g. using `git@github.com:pure-data/pd-lib-builder` is bad, because it requires everybody who wants to checkout your sources to have a github-account - even if they could checkout *your* repository anonymously. - submodules will be excluded from `git archive`. This means, that if you use a mainstream git provider (like Github, GitLab, Bitbucket,...) and make releases by creating a `git tag`, the automatically generated zipfiles with the sources will lack the submodule - and your users will not be able to compile your source code. In general, I would suggest to **avoid** `git submodule`, and instead use the better `git subtree` (above).