czardas Posted June 3, 2013 Author Posted June 3, 2013 czardas, you dawg. This is very cool! Outstanding work, glad to see this come to fruition. Yeah, it's been on the back of my mind for quite a while. Your comments and those of others helped me a lot back then, when I first mentioned it in dev chat. Thanks James. operator64 ArrayWorkshop
AZJIO Posted June 3, 2013 Posted June 3, 2013 o = 2400 ms + = 1200 ms ; = 600 ms default ... quarter note - = 300 ms ~ = 150 ms = 75 ms ? = 37.5 ms if the numbers /4 /8 /16, etc. My other projects or all
czardas Posted June 3, 2013 Author Posted June 3, 2013 (edited) Yes. A whole note (целая нота) is represented by the lower case letter o. Each subsequent note is divided by 2. o = 2400 ms, + = 2400/2 ms, ; = 2400/4 ms, - = 2400/8 ms etc... when the speed is 100 bpm (default). Edited June 3, 2013 by czardas operator64 ArrayWorkshop
monoceres Posted June 3, 2013 Posted June 3, 2013 I'm a complete idiot when it comes to music theory so I cannot really experiment with this, but I can recognize the great work. As someone who is very interesting in computer language theory and interpreter/compiler construction I have some feedback: You should definitely write a grammar for the language. EBNF is simple and the advantages of having your language in an abstract form is really useful and makes stuff a lot easier. Plus anyone else wanting to implement a interpreter/compiler knows exactly what to target. Split your interpreter into different parts. For something like this I think the following would be nice: - Lexer: Converts program into tokens. - Parser: Converts the tokens into an abstract syntax tree. This is basically the grammar represented in a tree data structure. If you have written in a grammar, it's easy to write a small recursive descent parser to parse the programs or use a parser generator such as ANTLR to generate a parser for you. - Evaluator: Simply takes your syntax tree and executes it. Having this separation is great because it's easy to debug, maintain and extend. It also allows you to do cool stuff like compile your programs without redoing all the work. Otherwise, it's a really cool project and hearing music from my speakers was a joy! jaberwacky and czardas 2 Broken link? PM me and I'll send you the file!
czardas Posted June 3, 2013 Author Posted June 3, 2013 (edited) monoceres, your expertize in programming languages is second to none and your input is much appreciated. I had already planned to write the instructions for making an interpreter in the near future. This week I'm busy with commitments, but after that I'll make a start. You have given me a lot of new information to absorb. I still need to look at where to draw the line between various errors and warnings, and how the interpreter should behave in all case scenarios. At the moment it throws stuff out that it doesn't like and tries to interpret the rest. The justification for this approach is that the ear also gives you feedback information and a warning system may sometimes be preferable to throwing an error. Edited June 3, 2013 by czardas operator64 ArrayWorkshop
monoceres Posted June 3, 2013 Posted June 3, 2013 I advice you to read up on grammars (EBNF), regex (for the lexer) and recursive descent parsers. With these three tools you will come a long way in making a good language. Error handling is massively simplified in a recursive descent parser. Since the parser is more or less a direct reflection of the grammar, everything that doesn't fit the grammar is directly identified as errors. Lets take a simple language that can add two digits together. The grammar in EBNF looks like this: <adder program> = <digit>,{"+",<digit>} <digit> = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" Some valid inputs for this grammar is: 1 1+2 1+2+1+5 While some invalid inputs are: [empty string] 1+ +1 2+4+ For fun, I wrote a little parser that evaluates the grammar: expandcollapse popup#include <array.au3> ; Grammar: ; <adder program> = <digit>,{"+",<digit>} ; <digit> = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; ; Displays error and terminates program. Func error($message) MsgBox(0,"Error",$message) Exit 1 EndFunc ; Token types Global Const $DIGIT = "digit" Global Const $PLUS = "plus" Global Const $END = "end" ; Returns a token! Func Token($type,$value=0) Return $type&"|"&$value EndFunc Func GetTokenValue($token) $arr = StringSplit($token,"|") return $arr[2] EndFunc Func GetTokenType($token) $arr = StringSplit($token,"|") return $arr[1] EndFunc ; Turns a string into an array of tokens. Func Lex($input) Local $res[1] ; Regex that matches tokens. Local $patterns[2][2] = [[$DIGIT,"^\d"],[$PLUS,"^\+"]] ; Repeat while there is characters left in input. while $input <> "" For $i=0 To UBound($patterns)-1 $value = StringRegExp($input,$patterns[$i][1],3) ; Did the pattern match! if not @error Then $value = $value[0] $input = StringTrimLeft($input,StringLen($value)) _ArrayAdd($res,Token($patterns[$i][0],$value)) ; Restart pattern loop. ContinueLoop 2 EndIf Next ; No pattern matched? Throw!! error("Could not scan string: "&$input) WEnd ; Insert special token for parser! _ArrayAdd($res,Token($END)) Return $res EndFunc Global $tokens Global $pos Global $current ; Throws error if current token is not of type. Func Expect($type) If GetTokenType($current)<>$type Then error("Expected token with type: "&$type&", got: "&GetTokenType($current)) EndFunc ; Returns true if current token is of type, else false. Func Accept($type) Return GetTokenType($current) == $type EndFunc ; Moves on to next token. Func Advance() $pos += 1 $current = $tokens[$pos] EndFunc ; Returns the value of digit token. Func Digit() Expect($DIGIT) Return Int(GetTokenValue($current)) EndFunc ; Parse/Executes an AdderProgram. Func AdderProgram() ; Setup parser $pos = 0 Advance() ; We know that each program starts with DIGIT. $sum = Digit() ; There can be infinite many repeating plus operation Advance() While Accept($PLUS) Advance() ; After accepting a PLUS we know there is a DIGIT following. $sum += Digit() Advance() WEnd ; We should have now reached the end of the program. ; If we're not at the END token, the program did not match grammar! Expect($END) Return $sum EndFunc $program = InputBox("Adder","Enter adder program:") $tokens = Lex($program) MsgBox(0,"Answer",$program&" = "&AdderProgram()) jaberwacky 1 Broken link? PM me and I'll send you the file!
czardas Posted June 3, 2013 Author Posted June 3, 2013 (edited) I understand the logic of your model and I thank you for taking the time to post it. Like other languages, mus++ has good and bad writing practice rules, most of which should be acceptable. The syntax is mainly based on existing rules governed by music theory, although in some cases interpretation can be specific to a style of music or, in others, a matter of opinion. For this reason there are still one or two details need ironing out. I was so happy when music came out of my speakers that I had to share my work even though It's far from complete. At least all the important features are already in place. Writing the tutorials has also helped me to clarify exactly how the language works. I will include some discussion of grammar and rules relating to syntax when I cover the remaining commands. Edited June 3, 2013 by czardas operator64 ArrayWorkshop
TheSaint Posted June 3, 2013 Posted June 3, 2013 I've finally had the sense to have a look at what you are on about and have done here, and I'm almost speechless ... which is something, coming from me. Truly amazing and mind-blowing, and I will certainly investigate this all fully when I get the time. Words cannot thank you enough for sharing this with us. P.S. I'd heard rumors it was good, but I'm still somewhat stunned. You're the man! Belated HAPPY BIRTHDAY! czardas 1 Make sure brain is in gear before opening mouth! Remember, what is not said, can be just as important as what is said. Spoiler What is the Secret Key? Life is like a Donut If I put effort into communication, I expect you to read properly & fully, or just not comment. Ignoring those who try to divert conversation with irrelevancies. If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it. I'm only big and bad, to those who have an over-active imagination. I may have the Artistic Liesense to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)
czardas Posted June 4, 2013 Author Posted June 4, 2013 (edited) @TheSaint I'm absolutely delighted that you like this, I know how much music means to you from our previous discussions. At the end of the day I don't believe you will ever be able to replace the human element in the process of creating music. This language is a tool, nothing more and nothing less. Thanks for taking a look at it and for your positive feedback. Edited June 4, 2013 by czardas TheSaint 1 operator64 ArrayWorkshop
TheSaint Posted June 4, 2013 Posted June 4, 2013 The least I can do after being tardy, and all the fine effort you have put into it. I also remember when you first started airing elements of this some time back, and I'm impressed big time at what you've made of it. Well done! czardas 1 Make sure brain is in gear before opening mouth! Remember, what is not said, can be just as important as what is said. Spoiler What is the Secret Key? Life is like a Donut If I put effort into communication, I expect you to read properly & fully, or just not comment. Ignoring those who try to divert conversation with irrelevancies. If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it. I'm only big and bad, to those who have an over-active imagination. I may have the Artistic Liesense to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)
czardas Posted June 7, 2013 Author Posted June 7, 2013 (edited) mus++ for non-musicians (Part 4) This and the next tutorial will introduce some more advanced features available in mus++. Many professional musicians will find some of this tough going, but it is necessary to cover everything the language is capable of. You may wish to use this material as more of a reference. It is better to try out one or two features until you get used to what they each do. I will also provide more examples in the future. The more theoretical elements at the end of the tutorial are not covered in great detail and leave some questions unanswered. I will try to cover some of these omissions in the next instalment. Many of these concepts will take time to assimilate. The keyword DC stands for Da Capo (Italian) and tells the interpreter to repeat from the start. The following plays the notes A B | C | A B | C2/4 A B | +C' DC With DC, bar repeats using colon occuring within the repeated section are ignored. The next example produces the sequence A B | C D | C D | E | A B | C D | E2/4 A B |: C' D :| +E DC With separate repeat endings the music goes immediately to the final ending and skips all other separate endings. The following example produces A B | A C | D | A C | D2/4 |: A 1, B :|2, C' | +D DC Instead of repeating from the start you can repeat from any earlier point using DS (Dal Segno => from the sign) in conjunction with a special symbol called segno represented by $ (dollar). The following example produces A | B C | D E | F C | D E | F2/4 A | B $ C' | D E | F DS The rules about ignoring repeated bar sections with DC also apply with DS. If the music continues after DC or DS, depending on which section you are in, repeat marks become active again. There are two ways to exit from within a section repeat. The first is to end the somewhere in the middle using the keyword fin (fine in Italian). Here we get A B | C | A B2/4 A B fin | +C' DC The second method to exit a repeated section is to use a coda represented by the capital letter Q. The coda is a tail section added on to the end of a piece of music. The coda symbol Q should appear twice - first at the escape point within the repeated section and then preceeded by a bar line after either DC or DS.2/4 A B Q | +C' DC |Q +E' The above plays the sequence A B | C | A B | E and the next example plays A B | C D | E F | C D | G2/4 A B | $ C' D | Q E F DS |Q +G In written music, the general rule with segno, coda and fine (in mus++ $ , Q & fin) are that these instructions should be ignored on first sight. When used in conjunction with DC (or DS) there is never any ambiguity in interpretation. However, you sometimes encounter coda or fine being used to escape a standard repeat section when no DC or DS instruction has been given. The performer is sometimes expected to decide (or know) how many times to repeat a section depending on context. Such ambiguity is not acceptable for a scripting language and separate endings can be used to achieve the same result. For this reason the 'ignore on first sight' rule is not entirely accurate, and in mus++ these symbols only apply when used together with DC or DS. The order and placement of segno, coda and fine are important. Here are some bad continuations - can you see why?fin $ DS fin Q DC |Q Q $ DS |Q 1, Q :| 2, DC |Q The following standard four continuations are recommended sequences, but other combinations are also possible.fin DC Q DC |Q $ fin DS $ Q DS |Q When a change in speed occurs, the new speed is maintained even after DC or DS. Besides manually setting the tempo using the standard syntax mentioned earlier, you can also use the macro @Tempo which returns the current speed to the speed at the start of the piece (strictly speaking the speed at which the first note, or rest, was played).5/4 @Tempo C D ;=190 E F G DC | _+-G @Tempo can be used at any point in the music. If you find this next section difficult, I advise you refer to the layout of the piano keyboard to help you. Remember the following rule: if a note is sharpened then it inherits the pitch of the next note on the right whether it be a white or a black key. If the note is flattened it aquires the pitch of the neighboring note on the left. A very useful instruction exists in music called a key signature. Key signatures make certain notes either sharp or flat by default. There are 15 possible key signatures each with a different selection of sharps or flats. In mus++ key signatures are notated by the number of notes affected. 4# means four sharps are included in the musical key. Likewise flat keys use lower case b. 1b means one note is flattened within the key. The default key is 0# (which is the same as 0b) and only includes the white notes on the piano keyboard. The following table gives the key signatures for all keys. Each note sequence is a major scale in a different key.Key Signatures with sharps0# = C major / A minor ... C D E F G A B C1# = G major / E minor ... G A B C D E F# G2# = D major / B minor ... D E F# G A B C# D3# = A major / F# minor ... A B C# D E F# G# A4# = E major / C# minor ... E F# G# A B C# D# E5# = B major / G# minor ... B C# D# E F# G# A# B6# = F# major / D# minor ... F# G# A# B C# D# E# F#7# = C# major / A# minor ... C# D# E# F# G# A# B# C#Key Signatures with flats0b = C major / A minor ... C D E F G A B C1b = F major / D minor ... F G A Bb C D E F2b = Bb major / G minor ... Bb C D Eb F G A Bb3b = Eb major / C minor ... Eb F G Ab Bb C D Eb4b = Ab major / F minor ... Ab Bb C Db Eb F G Ab5b = Db major / Bb minor ... Db Eb F Gb Ab Bb C Db6b = Gb major / Eb minor ... Gb Ab Bb C Db Eb Fb Gb7b = Cb major / Ab minor ... Cb Db Eb Fb Gb Ab Bb Cb Learning all the above combinations seems a daunting task and many musicians are uncomfortable with certain keys because of the nature of the instrument they play. Some instruments are more suited to certain keys for example the guitar - due to way the instrument is tuned. The length of the air pipe in wind instruments is another influencing factor. In the following example all notes written as B sound as Bb.1b 4/4 F G A B | A G +F | ;B B A G | oF The order in which sharps and flats are introduced in key signatures is fixed.key ....... 1# 2# 3# 4# 5# 6# 7# New Note .. F# C# G# D# A# E# B# The order that flats are introduced turns out to be the reverse.key ....... 1b 2b 3b 4b 5b 6b 7b New Note .. Bb Eb Ab Db Gb Cb Fb Personally I use a mneumonic, which also works in reverse, to remember this sequence:Father Charles Goes Down And Ends Battle.Battle Ends And Down Goes Charle's Father. We end this tutorial with Tuplets. We have already discussed dividing a note into three equal durations using triplets, but what about other more complicated divisions. This is very easy in mus++. To do this you simply write the number you wish to divide by before brackets. The following would divide a half note + into 5 equal parts (quintuplet).5(- - - - -) There are limits to how many equal divisions you can have in mus++. In music you normally don't come across divisions of more than 11 because most musicians find such divisions difficult to perform accurately. Furthermore numbers with prime factors can be simplified and numbers which are a power of 2 (duplets) are interpreted differently. More about duplets later. The following guide shows which notes to use when dividing different note durations. The first column shows the total duration.Duration Divisions ..................................... 3 5to7 9to15 17to31 33to63 65to127 ? ~ ? - ~ ? ; - ~ ? + ; - ~ ? o + ; - ~ ? The general rule is that the duration of the tuplets would be longer if not compressed to fit within the associated note value in the first column.4/4 - - (- - -) ~ ~ ~ ~ 7(~ ~ ~ ~ ~ ~ ~) | o The system covers most musically meaningful divisions. The following musical example (taken from wiki) shows five beats divided into six equal parts. This is difficult to perform and uses a ratio (6:5) to indicate the division. Using ratios to denote rhythmic divisions is not currently planned as a feature in mus++. The wiki example can also be notated in other ways including the following:5/4 6( ;~ ~; ;~ ~; ;~ ~; ) Examples using the features from the 4th tutorial _MusPlusPlus( _ ; Irregular Jazz Rhythm - mus++ Example by czardas "<tpt> 2b 4/4 ;=109 $ C' |: _7(+.C -'F#') 7(G B 'Bz' C' E Fb D) | 1, +'G' ;E' C :| 2, Q +'G' _7(~G ;=133 -.E' Ez) DS |Q @Tempo +'G' (-G G G) ;G | _+G ;") Edited June 9, 2013 by czardas operator64 ArrayWorkshop
Mat Posted June 7, 2013 Posted June 7, 2013 Czardas, for years you have been rambling about music this and music that in some dark basement of the forum... Perhaps there was method in the madness! Maybe I'll convert some coldplay over to this. Their tunes are always very easy. czardas 1 AutoIt Project Listing
BrewManNH Posted June 7, 2013 Posted June 7, 2013 Time to start the dreaded documentation for this, this would be great as a project for a help file or wiki site. I think that the http://www.wikia.com site might be a place to start to think about something like this. If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays. - ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script. - Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label. - _FileGetProperty - Retrieve the properties of a file - SciTE Toolbar - A toolbar demo for use with the SciTE editor - GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI. - Latin Square password generator
czardas Posted June 7, 2013 Author Posted June 7, 2013 (edited) Time to start the dreaded documentation for this, this would be great as a project for a help file or wiki site. I think that the http://www.wikia.com site might be a place to start to think about something like this. Yes, after I have cleaned up one or two things. I thought I might be able to finish describing all the current features in my previous post, but I decided it would be too much in one go. There's not so much left to describe, but descriptions can be complicated. That's what I'm experiencing with this, and the reason why examples are so useful. I would like to be able to dedicate more time to my projects. I have to plod along in the time available. Edited June 7, 2013 by czardas operator64 ArrayWorkshop
czardas Posted June 9, 2013 Author Posted June 9, 2013 (edited) New secrets revealed: Compair the two examples from >post #34 with the following versions which use features introduced in the 4th tutorial. The sections repeat in a typical fashion. Notice how all the sharps (#) have disappeared from the code for 'The Oysterwives Rant'. They are no longer needed because of the key signature. This is much better organised code. ; _MusPlusPlus( _ ; The Oysterwives Rant "<fiddle> 2# 4/4 ;=125 |: $ -A | ;B -B A B E E F | A B A F D E F A | ;B -B A B C' D 'B' | A F D' 'F' Q ;E -E ;=128 :|" & _ ";=131 |: A | B A B C' D E D 'B' | -.A ~B -A F -.A ~B ;=75 ~.A \ ;=131 -F | B A B C' D E D 'B' | A F D' 'F' ;E -E ;=134 :|" & _ ";=137 DS |Q @Tempo ;E -;.E") Sleep(2000) _MusPlusPlus( _ ; O'er The Muir Amang The Heather "<bagp> 4/4 ;=90 -E' |: $ ;'G' -.G ~B ;G -.G ~B | ;A -.A ~B -D' 'G' B G | -.D' ~E -.D ~'B' -.D' ~E -.G ~A| G F -E -.G ~'B' -.A ~B -.A ~G :|" & _ "|: -.G ~B -.G' ~A G F -E | -.G ~D E -.A A ~G ;A | -.A ~E -.G ~A G F -E -.D ~E -.G ~A | G F -E -.G ~'B' Q -.A ~B -.A ~G :| DS |Q ;.A") ; ; And now an example of use with AutoIt - Random Greek Mode generator ; ; An example of using mus++ with AutoIt ; Random Greek Mode generator Local $sKey, $aSequence[7] = [ _ "-C D E F G A B C' 'B' A G F E D -oC", _ "-D E F G A B C' D C 'B' A G F E -oD", _ "-E F G A B C' D E D C 'B' A G F -oE", _ "-F G A B C' D E F E D C 'B' A G -oF", _ "-G A B C' D E F G F E D C 'B' A -oG", _ "-A B C' D E F G A G F E D C 'B' -oA", _ "-B C' D E F G A B A G F E D C -o'B'"] For $i = 1 To 21 If Random(0, 1, 1) Then $sKey = "#" Else $sKey = "b" EndIf _MusPlusPlus(Random(0, 7, 1) & $sKey & " ;=200 " & $aSequence[Random(0, 6, 1)]) Next ; Edited June 9, 2013 by czardas jaberwacky 1 operator64 ArrayWorkshop
czardas Posted June 13, 2013 Author Posted June 13, 2013 (edited) mus++ for non-musicians (Part 5) This final installment brings together all the elements of the previous tutorials and introduces the remaining features of mus++. Firstly lets deal with some syntax. The order you should place performance instructions is as follows: instrument, key signature, time signature and finally tempo markings followed by the music. You may also miss out any of the above.<fl> 2# 6/8 ;=120 ;'B' -C' ;'B' -A | ;B -C' ;.D So far we have only discussed notes appearing within the mid pitch range, and those appearing one octave above or below that. You can go up or down more octaves by adding more quotes to the right or the left of the note name. The lowest note (in midi) is ''''A , and the highest note is C'''' . It is possible to use a double quote in place of two single quotes, so the full range of notes can also be expressed as ""A to C"" . Duplets are special tuplets which are used to divide a dotted note into two or four equal divisions. <fl> 2# 6/8 ;=120 |: -C' 'B' C' 2('A' A) | A B C' 1, D C 'B' :|2, ;.D Duplets are different from other tuplets because the sum of the note durations would be less than the associated dotted note (shown in the first column below) if the notes were played normally. Any tuplet division which is a power of 2 is interpreted as a duplet. Duration Divisions ································ 2 4 8 16 32 64. ? ~. ? -. ~ ? ;. - ~ ? +. ; - ~ ? o. + ; - ~ ? If you wish to make a line break in a single voice, you must leave an empty line between each break. If you do not do this, the interpreter will see the new line as a new voice or instrument.2/4 ~'''C D E F | G A B ''C D E F G |A B 'C D E F G A | B 'C' D E F G A B | +C' When writing for more than one voice, it is important to write all performance instructions out in full in each voice - that is if you wish to keep the voices synchronized - this is not forced.<pno> 4/4 ;=140 -C D E F G F E D | oC <pno> 4/4 ;=140 ''C '''B G F | o''C The current interpreter allows you to use up to eight voices. If you insert an empty line as a break, you must maintain the same number of voices (consecutive lines) after the break. This final section covers some more advanced theory related to key signatures and accidentals. Consider the following scale - Cb major - in which all the notes have been flattened.Cb Db Eb Fb Gb Ab Bb Cb' This can be written using the key signature 7b:7b C D E F G A B C' To sharpen a note in this scale, you must use a natural sign z.7b C D E Fz G A B C' To flatten a note, you must use another accidental called a double flat bb.7b C D E F G A Bbb C' Similar rules apply when a note is already sharpened in the key signature. In this case you use a natural sign z to flatten, and a double sharp x to sharpen the note.4# C D E Fx G A B C' Double sharps and double flats are generally quite rare, but their existance is a consequence of the major/minor key system used in Western harmonic theory. From personal observation, I would have to say that some note names are difficult to justify - for example Cbb, because such a name appears to have no harmonic significance in any musical key. Instead of Cbb, it is more meaningful to call this particular note Bb. Of course you can use the symbols in mus++ any way you like. Another important fact about the key system is that some keys are actually duplicates. The key F# major contains the same pitch values as Gb major, but the notes are named differently. The following two scales are identical.6# F G A B C' D E F 6b G A B C' D E F G Also 7# contains the same set of pitch values as 5b, and likewise 5# is the same as 7b. This covers all the features included in this first release of mus++. There will not be any changes to the use of the symbols included here. Additional features may be added at a later date. Edited June 13, 2013 by czardas operator64 ArrayWorkshop
czardas Posted June 16, 2013 Author Posted June 16, 2013 (edited) It's remarkable how much the visual appearance of mus++ reminds me of the old pianola rolls. I'm sure you'll like this one - it's a big favourite of mine: ; expandcollapse popup#include-once #include <Array.au3> _MusPlusPlus( _ ; An der schonen blauen Donau "<br pno> 2# 3/4 ;=156 +. | +. | +. | +. | +. | +. | +. | +. | +. | +. |" & @CR & _ "<br pno> 2# 3/4 ;=156 +. | ; ; A'| A ; F | F + | +. | ; ; A | A ; G | G + | +. | ; ; B |" & @CR & _ "<br pno> 2# 3/4 ;=156 +. | ; ; F'| F ; D | D + | +. | ; ; G | G ; C | C + | +. | ; ; G |" & @CR & _ "<br pno> 2# 3/4 ;=156 D F G | +.A |_+;A |_A ; D | D G A | +.A |_+;A |_A ; C | C E B | +.B |" & @CR & _ "<br pno> 2# 3/4 ;=156 +. | ; F F | ; F F | ; D ; | ; ; F | G G G |_G G G |_G C ; | ; C C | ; G G |" & @CR & _ "<br pno> 2# 3/4 ;=156 +. | ; D D | ; D D | ; 'A A | ; 'D' D | ; C C | ; C C | ; 'A A | ; A A | ; 'C' C |" & @CR & _ "<br pno> 2# 3/4 ;=156 +; |'D A A | D A A | D F F | D A A | E A A | E A A | E G G | E G G |''A 'A A |" & @CR & _ @CR & _ " +. | +. | +. | ; ; B'| B + | +. | +. | +. | +. | +. | +. |" & @CR & _ " B ; G | G + | +. | ; ; F | F ; F | F + | +. | ; ; D''| D ; A'| A + | +. |" & @CR & _ " G ; C | C + | +. | ; ; D | D ; D | D + | +. | ; ; A | A ; F | F + | +. |" & @CR & _ "_+;B |_B ; C | C E B | +.B |_+;B | A ; D | D F A | +.D' |_+;D |_D ; 'D'| D F A |" & @CR & _ " ; G G | ; C ; | ; C C | ; F F | ; F F | ; D ; | ; ; F | +. | +. | ; D ; | +. |" & @CR & _ " ; C C | ; 'A A | ; A A | ; 'D' D | ; D D | ; 'A A | ; 'D' D | ; D D | ; D D | ; 'A A | ; 'D' D |" & @CR & _ "''A 'A A |''A 'G G |''A ;'G G | D A A | D A A | D F F | D A A | F A A | F A A | F ; F | F A A |" & @CR & _ @CR & _ " +. | +; | B + | +. | +. | +. | +. | +. | +. | +. | +. ;=60 |" & @CR & _ " ; ; D''| D ; B'| E ; E | E G -B - | +;B |_B G# A | +;F'' |_F D ; | +F' ;E | +B ;A | D - D ;D ;=60 |" & @CR & _ " ; ; B | B ; E |'E' + | +. | +. | +. | +. | +. | E | +. | ; - A ;A ;=60 |" & @CR & _ " ;+D' |_D ;D |_D ; 'E'| E G -B - | +;B |_B G# A | +;F |_F D F | +.'B' | C' | ; - 'F' ;F ;=60 |" & @CR & _ " ; E E | ; E E | D + | +. | ; G G | ; Gz G | ; F F | +. | D |'G | +. ;=60 |" & @CR & _ " ; D D | ; D D |'B + | +. | ; 'C' C | ; C C | ; D D | ; D D | +.'B | +;E | F ; A ;=60 |" & @CR & _ " G B B | G B B | G ; E | +; | E A A |''A 'A A | D A A | F A A | +.G | +;''A | 'D ; D ;=60 |" & @CR & _ @CR & _ " 3# ; @Tempo + |: +. | +. | +. | +. | +. | +. |" & @CR & _ " 3# ; @Tempo -D'' - C - |: C - B' - B - | ; -B - A# - | A# - B - B - | ; -E - E - | +F ;E | ; -E - E - |" & @CR & _ " 3# ; @Tempo ; ; |: +. | +. | +. | +. | +. | +. |" & @CR & _ " 3# ; @Tempo -F' - E - |: E - D - D - | ; -D - C - | C - D - D - | +. | +. | +. |" & @CR & _ " 3# ; @Tempo + |: ; 'E' E | ; E E | ; E E | ; D D | ; C C | ; C C |" & @CR & _ " 3# ; @Tempo + |: ; 'D' D | ; D C | ; D D | ; 'G G | ; A A | ; A A |" & @CR & _ " 3# ; @Tempo ; ; |: E G G | E G Gz | E G G |''E 'E E |''A 'E E |''A 'E E |" & @CR & _ @CR & _ " +. | +. | +. | +. | +. | +. | +. | + - - |" & @CR & _ " +B ;A | ; -D'' - C - | C - B' - B - | ; -B - C'' - | E - D - D - | ; -G' - B - | +B ;A | ;-G F D 'B'|" & @CR & _ " +. | +. | +. | + -A#' - | C'' - B' - B - | ; 'D' D | +. | + - - |" & @CR & _ " +'B' ;A | ; -F' - E - | E - D - D - | ; -D - C - | E - D - D - | ; -'G' - B - | +B ;A | ;.G ;- |" & @CR & _ " ; C C | ; D C | ; D D | ; D C | ; D D | ; 'B B | ;+'C' | B' ; |" & @CR & _ " ; A A | ; A A | ; G G | ; G Gz | ; G G | ; ; G | +B ;A | +F ; |" & @CR & _ " ''A 'E E |''A 'F E |''E 'E E |''E 'E E |''E 'E E |''E E' E# | +.F | +D ; |" & @CR & _ @CR & _ " B B ;B B |1, +. :|2, ; fin + | +. | +. | +. DC" & @CR & _ " F' F ;F E |1, 'A' -D'' - C - :|2, 'A' fin + | +.A' |_+.A' |_;A + DC" & @CR & _ " D' D ;D D |1, 'E' + :|2, 'E' fin + | +. | +. | +. DC" & @CR & _ " G G ;G G |1, C -F' - E - :|2, C fin + | +. | +. | +. DC" & @CR & _ " E G E |1, A ; ; :|2, A fin + | +.'Gz' | +;E | Gz + DC" & @CR & _ " +. |1, +. :|2, ; fin + | +.'E' | +;'A | 'E' + DC" & @CR & _ "''E G E |1, A ; ; :|2, A fin + | +. | +. | +. DC") Func _MusPlusPlus($sSource) ; Parse mus++ $sSource = _InitialTidySource($sSource) If @error Then Return SetError(1, 0, 0) Local $iParts = 8, $aSystems = StringSplit($sSource, @LF & @LF, 1) Local $aVoices[$iParts] = ["","","","","","","",""], $aStaves For $i = 1 To $aSystems[0] $aStaves = StringSplit($aSystems[$i], @LF) If $i = 1 And $aStaves[0] <= 8 Then $iParts = $aStaves[0] ReDim $aVoices [$iParts] ElseIf $iParts <> $aStaves[0] Then Return SetError (2, 0, 0) ; Inconsistant number of voices EndIf For $j = 0 To $iParts -1 $aVoices[$j] &= " " & $aStaves[$j +1] Next Next Local $aTimeLine, $aRepeat[1][11], $iInstance, $vCurrInstrument, $vCurrKey, $sCurrNote, $iCurrOctave, $sLookFor, $sSegnoInstrument, _ $sSegnoKey, $iSegnoOctave, $sSegnoNote, $iLatestInstrument, $iLatestKey, $iCurrRepeat, $iEndings, $iSegno, $iDalSegno, $iDaCapo, _ $aAccidentals[7], $sSegnoAccidentals, $sAtTempo, $vCurrTempo, $aNotePart, $sSkipIndex, $sWarnings = "", $sErrors = "", $iTuplet, _ $bTie, $bRest, $iPitch, $iBound =1, $aInstrument[$iParts], $iHangCheck, $iRepeats, $iCurrTime, $aMessage[$iParts][1][2] ;==> voice|instance|params=time/msg Local Enum $iEntry = 0, $iEntryInstrument, $iEntryKey, $iEntryOctave, $iEntryNote, $iFirstExit, $iFirstExitOctave, _ $iFirstExitNote, $iFinalExit, $iFinalExitInstrument, $iFinalExitKey For $i = 0 To $iParts -1 $aInstrument[$i] = 0xC0 Next ; Parsing begins here For $i = 0 To $iParts -1 _ClearAccidentals($aAccidentals) $aVoices[$i] = StringStripWS($aVoices[$i], 3) StringReplace($aVoices[$i], "|:", "") ; Get loop entry points If @extended Then ReDim $aRepeat[@extended +1][11] $iInstance = 0 ; bar repeat sections encountered $vCurrInstrument = "<pno>" ; piano $vCurrKey = "0#" ; C major / A minor $sCurrNote = ";" ; quarter note $iCurrOctave = 4 $sLookFor = "" ; Look for Q or fin within a DC or DS section repeat ; Bar repeat data $aRepeat[$iInstance][$iEntry] = $iInstance $aRepeat[$iInstance][$iEntryInstrument] = $vCurrInstrument $aRepeat[$iInstance][$iEntryKey] = $vCurrKey $aRepeat[$iInstance][$iEntryOctave] = $iCurrOctave $aRepeat[$iInstance][$iEntryNote] = $sCurrNote $aRepeat[$iInstance][$iFirstExit] = $iInstance $aRepeat[$iInstance][$iFirstExitOctave] = $iCurrOctave $aRepeat[$iInstance][$iFirstExitNote] = $sCurrNote $aRepeat[$iInstance][$iFinalExit] = "" $aRepeat[$iInstance][$iFinalExitInstrument] = $vCurrInstrument $aRepeat[$iInstance][$iFinalExitKey] = $vCurrKey $iCurrRepeat = 1 ; First iteration of a bar repeat sequence $iEndings = 1 ; no separate bar repeat endings encountered yet $aTimeLine = StringRegExp($aVoices[$i], "[^\h]+", 3) $aVoices[$i] = "" $sSegnoInstrument = $vCurrInstrument ; Section repeat data $sSegnoKey = $vCurrKey ; Section repeat data => $iSegnoOctave = $iCurrOctave $sSegnoNote = $sCurrNote $sSegnoAccidentals = ",,,,,," ; array is needed when $ occurs after an accidental $iLatestInstrument = 0 ; position in timeline $iLatestKey = 0 ; position in timeline $iSegno = -1 ; position of $ $iDalSegno = -1 ; position of DS $iDaCapo = -1 ; position of DC $sAtTempo = -1 $vCurrTempo = ";=100" $sSkipIndex = "|" For $j = 0 To UBound($aTimeLine) -1 If StringInStr($sSkipIndex, "|" & $j & "|") Then ContinueLoop $iHangCheck = $j -1 Select Case _IsInstrument($aTimeLine[$j]) If $j > $iLatestInstrument Then $iLatestInstrument = $j _UpdateCurrentAttrib($vCurrInstrument, $aVoices, $aTimeLine[$j], $i) $aRepeat[$iInstance][$iEntryInstrument] = $vCurrInstrument ; Temporary Patch Case _IsKeySig($aTimeLine[$j]) If $j > $iLatestKey Then $iLatestKey = $j _UpdateCurrentAttrib($vCurrKey, $aVoices, $aTimeLine[$j], $i) Case _IsTempoMark($aTimeLine[$j]) If Not StringRegExp($aVoices[$i], "[A-Go\+;\-~\\\?]") Then $sAtTempo = $aTimeLine[$j] EndIf _UpdateCurrentAttrib($vCurrTempo, $aVoices, $aTimeLine[$j], $i) Case _IsAtTempo($aTimeLine[$j]) _UpdateCurrentAttrib($vCurrTempo, $aVoices, $sAtTempo, $i) Case _IsSegno($aTimeLine[$j]) $sSegnoKey = $vCurrKey $sSegnoInstrument = $vCurrInstrument $iSegnoOctave = $iCurrOctave $sSegnoNote = $sCurrNote $iSegno = $j $sSegnoAccidentals = "" For $k = 0 To 5 $sSegnoAccidentals &= $aAccidentals[$k] & "," Next $sSegnoAccidentals &= $aAccidentals[6] Case _IsBarLine($aTimeLine[$j]) _ClearAccidentals($aAccidentals) Case _IsStartRepeat($aTimeLine[$j]) _ClearAccidentals($aAccidentals) $iInstance += 1 If $j > $iDaCapo And $j > $iDalSegno Then $aRepeat[$iInstance][$iEntry] = $j $aRepeat[$iInstance][$iEntryInstrument] = $vCurrInstrument $aRepeat[$iInstance][$iEntryKey] = $vCurrKey $aRepeat[$iInstance][$iEntryOctave] = $iCurrOctave $aRepeat[$iInstance][$iEntryNote] = $sCurrNote $iCurrRepeat = 1 $iEndings = 1 EndIf Case _Is2ndTimeRound($aTimeLine[$j]) If $j > $iDaCapo And $j > $iDalSegno Then If $aRepeat[$iInstance][$iFinalExit] = "" Then $aRepeat[$iInstance][$iFirstExit] = $j $aRepeat[$iInstance][$iFirstExitOctave] = $iCurrOctave $aRepeat[$iInstance][$iFirstExitNote] = $sCurrNote EndIf $iRepeats = StringTrimRight($aTimeLine[$j], 1) ; string to number If $iEndings < $iRepeats Then $iEndings = $iRepeats If $iCurrRepeat > $iRepeats Then If $vCurrKey <> $aTimeLine[$iLatestKey] Then If _IsKeySig($aTimeLine[$iLatestKey]) Then $vCurrKey = $aTimeLine[$iLatestKey] $aVoices[$i] &= $vCurrKey & " " EndIf EndIf _UpdateCurrentAttrib($vCurrInstrument, $aVoices, $aTimeLine[$iLatestInstrument], $i) _ClearAccidentals($aAccidentals) $j = $aRepeat[$iInstance][$iFinalExit] ; Go to the next end repeat mark EndIf Else $j = $aRepeat[$iInstance][$iFinalExit] ; Go directly to the last end section _ClearAccidentals($aAccidentals) _UpdateCurrentAttrib($vCurrKey, $aVoices, $aRepeat[$iInstance][$iFinalExitKey], $i) _UpdateCurrentAttrib($vCurrInstrument, $aVoices, $aRepeat[$iInstance][$iFinalExitInstrument], $i) EndIf Case _IsTie($aTimeLine[$j]) Or _IsStartTuplet($aTimeLine[$j]) Or _IsEndTuplet($aTimeLine[$j]) $aVoices[$i] &= $aTimeLine[$j] & " " Case _IsNote($aTimeLine[$j]) $aNotePart = _NoteSplit($aTimeLine[$j]) If $aNotePart[0] <> "" Then $sCurrNote = _GetCurrNote($aNotePart[0]) EndIf If $aNotePart[1] <> "" Then If StringInStr($aNotePart[1], "'") Then $iCurrOctave = _GetOctave($aNotePart[1]) EndIf If StringRegExp($aNotePart[1], "[#bxz]") Then _UpdateAccidentals($aAccidentals, $aNotePart[1]) Else _GetAccidental($aAccidentals, $aNotePart[1]) EndIf EndIf $aVoices[$i] &= $aNotePart[0] & $aNotePart[1] & " " If $sAtTempo = -1 Then $sAtTempo = $vCurrTempo Case _IsEndRepeat($aTimeLine[$j]) If $j > $iDaCapo And $j > $iDalSegno Then _ClearAccidentals($aAccidentals) If $iCurrRepeat = $iEndings Then $aRepeat[$iInstance][$iFinalExit] = $j $aRepeat[$iInstance][$iFinalExitInstrument] = $vCurrInstrument $aRepeat[$iInstance][$iFinalExitKey] = $vCurrKey EndIf If $iCurrRepeat <= $iEndings Then ; Go back to the start of the loop $j = $aRepeat[$iInstance][$iEntry] ; $j will be incremented on the next pass ^^ $iCurrRepeat += 1 _UpdateCurrentAttrib($vCurrKey, $aVoices, $aRepeat[$iInstance][$iEntryKey], $i) _UpdateCurrentAttrib($vCurrInstrument, $aVoices, $aRepeat[$iInstance][$iEntryInstrument], $i) _UpdateCurrentAttrib($iCurrOctave, $aVoices, $aRepeat[$iInstance][$iEntryOctave], $i, "{", "} ") _UpdateCurrentAttrib($sCurrNote, $aVoices, $aRepeat[$iInstance][$iEntryNote], $i, "{", "} ") EndIf EndIf Case _IsDalSegno($aTimeLine[$j]) If $iDalSegno < $j Then If $iSegno = -1 Then $sWarnings &= "Voice " & $i +1 & " Warning => Expected $ sign before DS " & @CRLF ConsoleWrite($sWarnings) ; deal with this later ExitLoop ; further parsing of this voice is meaningless EndIf $iDalSegno = $j $j = $iSegno $sLookFor = "DS" _UpdateCurrentAttrib($vCurrKey, $aVoices, $sSegnoKey, $i) _UpdateCurrentAttrib($vCurrInstrument, $aVoices, $sSegnoInstrument, $i) _UpdateCurrentAttrib($iCurrOctave, $aVoices, $iSegnoOctave, $i, "{", "} ") _UpdateCurrentAttrib($sCurrNote, $aVoices, $sSegnoNote, $i, "{", "} ") $aAccidentals = StringSplit($sSegnoAccidentals, ",", 2) For $iInstance = $iInstance To 0 Step -1 If $iSegno > $aRepeat[$iInstance][$iEntry] Then ExitLoop Next EndIf Case _IsDaCapo($aTimeLine[$j]) If $iDaCapo < $j Then _ClearAccidentals($aAccidentals) $iDaCapo = $j $j = -1 $sLookFor = "DC" $iInstance = 0 _UpdateCurrentAttrib($vCurrKey, $aVoices, $aRepeat[$iInstance][$iEntryKey], $i) _UpdateCurrentAttrib($vCurrInstrument, $aVoices, $aRepeat[$iInstance][$iEntryInstrument], $i) _UpdateCurrentAttrib($iCurrOctave, $aVoices, $aRepeat[$iInstance][$iEntryOctave], $i, "{", "} ") _UpdateCurrentAttrib($sCurrNote, $aVoices, $aRepeat[$iInstance][$iEntryNote], $i, "{", "} ") EndIf Case _IsCoda($aTimeLine[$j]) If ($sLookFor = "DS" And $j < $iDalSegno) Or ($sLookFor = "DC" And $j < $iDaCapo) Then If $iDalSegno > $iDaCapo Then $j = $iDalSegno Else $j = $iDaCapo EndIf _UpdateCurrentAttrib($vCurrKey, $aVoices, $aTimeLine[$iLatestKey], $i) _UpdateCurrentAttrib($vCurrInstrument, $aVoices, $aTimeLine[$iLatestInstrument], $i) EndIf Case _IsFin($aTimeLine[$j]) If ($sLookFor = "DS" And $j < $iDalSegno) Or ($sLookFor = "DC" And $j < $iDaCapo) Then ExitLoop Case Else If _IsTimeSig($aTimeLine[$j]) Or _IsTechnique($aTimeLine[$j]) Or _IsBarRepeat($aTimeLine[$j]) Or _IsAccel($aTimeLine[$j]) Or _IsDynamicMark($aTimeLine[$j]) Then ContinueLoop ; Currently unsupported performance instructions or features Else $sErrors &= "Voice " & $i +1 & " Syntax Error => " & $aTimeLine[$j] & @CRLF $sSkipIndex &= $j & "|" ConsoleWrite("Voice " & $i +1 & " Syntax Error => " & $aTimeLine[$j] & @LF) EndIf EndSelect If $j = $iHangCheck Then $j += 1 ; Recursion correction Next ;ConsoleWrite($aVoices[$i] & @LF) $aTimeLine = StringRegExp($aVoices[$i], "[^\h]+", 3) $iInstance = UBound($aTimeLine)*2 ; upper limit... variable re-usage If $iInstance > UBound($aMessage, 2) Then ReDim $aMessage [$iParts][$iInstance][2] $vCurrInstrument = 0 $iLatestInstrument = 0 $vCurrKey = 0 ; C major / A minor $iLatestKey = 0 ; C major / A minor $vCurrTempo = 100 $iCurrOctave = 4 $sCurrNote = ";" $sLookFor = -1 ; variable re-usage $bTie = False ; variable re-usage $bRest = True $iInstance = 0 ; message count $iCurrTime = 0 $iTuplet = 1 Local $iDuration For $j = 0 To UBound($aTimeLine) -1 Select Case _IsInstrument($aTimeLine[$j]) $aTimeLine[$j] = StringRegExpReplace($aTimeLine[$j], "(_)(pno|box|org|acc|gtr|bass|tpt|sax|hn|drum|bl)", " " & "$2") $iLatestInstrument = _GetInstrument($aTimeLine[$j]) If @error And Not StringInStr($sErrors, $aTimeLine[$j]) Then $sErrors &= "Voice " & $i +1 & " Instrument not recognized => " & $aTimeLine[$j] & @CRLF ConsoleWrite("Voice " & $i +1 & " Instrument not recognized => " & $aTimeLine[$j] & @LF) ElseIf $vCurrInstrument <> $iLatestInstrument Then $vCurrInstrument = $iLatestInstrument $aMessage[$i][$iInstance][0] = $iCurrTime $aMessage[$i][$iInstance][1] = $vCurrInstrument*256 + 0xC0 $iInstance += 1 EndIf $aInstrument[$i] = $vCurrInstrument*256 + 0xC0 Case _IsKeySig($aTimeLine[$j]) $vCurrKey = _GetKey($aTimeLine[$j]) Case _IsTempoMark($aTimeLine[$j]) $vCurrTempo = _GetQuartNoteBPM($aTimeLine[$j]) Case _IsTie($aTimeLine[$j]) $bTie = True Case _IsStartTuplet($aTimeLine[$j]) $iTuplet = StringReplace($aTimeLine[$j], "(", "") If $iTuplet = "" Then $iTuplet = 3 Case _IsOctave($aTimeLine[$j]) $iCurrOctave = StringRegExpReplace($aTimeLine[$j], "[\{\}]", "") Case _IsCurrentNote($aTimeLine[$j]) $sCurrNote = StringRegExpReplace($aTimeLine[$j], "[\{\}]", "") Case _IsNote($aTimeLine[$j]) $aNotePart = _NoteSplit($aTimeLine[$j]) If $aNotePart[0] <> "" Then $sCurrNote = _GetCurrNote($aNotePart[0]) Else $aNotePart[0] = $sCurrNote EndIf $iDuration = _GetDuration($aNotePart[0], $vCurrTempo, $iTuplet) If $aNotePart[1] <> "" Then If StringInStr($aNotePart[1], "'") Then $iCurrOctave = _GetOctave($aNotePart[1]) EndIf If Not $bTie Then $aMessage[$i][$iInstance][0] = $iCurrTime $iPitch = _GetPitch($aNotePart[1], $vCurrKey, $iCurrOctave) $aMessage[$i][$iInstance][1] = BitOr(($iPitch+0x15)*256, 0x90, 0x400000) ; Midi note on $iInstance += 1 Else If Not $bRest And $sLookFor > -1 Then $aMessage[$i][$sLookFor][0] += $iDuration EndIf EndIf $bRest = False Else $bRest = True EndIf $iCurrTime += $iDuration If Not $bRest And Not $bTie Then ; Now turn note off $aMessage[$i][$iInstance][0] = $iCurrTime $aMessage[$i][$iInstance][1] = BitXOR($aMessage[$i][$iInstance -1][1], 0x400000) ; Midi note off $sLookFor = $iInstance $iInstance += 1 EndIf $bTie = False Case _IsEndTuplet($aTimeLine[$j]) $iTuplet = 1 EndSelect Next If $iInstance > $iBound Then $iBound = $iInstance Next ReDim $aMessage[$iParts][$iBound][2] ;_WalkThrough3D($aMessage) ; Debugging - Requires arratf.au3 $sLookFor = "" For $i = 0 To $iParts -1 For $j = 0 To UBound($aMessage, 2) -1 If $aMessage[$i][$j][0] == "" Then ExitLoop If Not StringInStr($sLookFor, "," & $aMessage[$i][$j][0] & ",") Then $sLookFor &= $aMessage[$i][$j][0] & "," EndIf Next Next $aTimeLine = StringSplit(StringTrimRight($sLookFor, 1), ",", 2) _ArraySortByNumber($aTimeLine) If $aTimeLine[1] = 0 Then _ArrayDelete($aTimeLine, 0) Local $aGrid[UBound($aTimeLine)][$iParts*8 +3] For $i = 0 To UBound($aTimeLine) -1 $aGrid[$i][0] = 1 $aGrid[$i][1] = $aTimeLine[$i] Next For $i = $iParts -1 To 0 Step -1 $iInstance = 0 For $j = 0 To UBound($aMessage, 2) -1 If $aMessage[$i][$j][0] == "" Then ExitLoop If $aMessage[$i][$j][0] == $aTimeLine[$iInstance] Then If BitAND($aMessage[$i][$j][1], 0x400000) = 0x400000 Then If $aGrid[$iInstance][$aGrid[$iInstance][0]] <> $aInstrument[$i] Then $aGrid[$iInstance][0] += 1 $aGrid[$iInstance][$aGrid[$iInstance][0]] = $aInstrument[$i] EndIf EndIf $aGrid[$iInstance][0] += 1 $aGrid[$iInstance][$aGrid[$iInstance][0]] = $aMessage[$i][$j][1] ElseIf $aMessage[$i][$j][0] > $aTimeLine[$iInstance] Then $iInstance += 1 If $iInstance > UBound($aTimeLine) -1 Then ExitLoop $j -= 1 EndIf Next Next ;_ArrayDisplay($aGrid) Local $iTimer, $dOpen = _MidiOutOpen() $iInstance = 0 $iTimer = TimerInit() While 1 If TimerDiff($iTimer) >= $aGrid[$iInstance][1] Then For $i = 2 To $aGrid[$iInstance][0] _MidiOutShortMsg($dOpen, $aGrid[$iInstance][$i]) Next $iInstance += 1 Else Sleep(10) EndIf If $iInstance > UBound($aTimeLine) -1 Then ExitLoop WEnd Sleep(600) _MidiOutClose($dOpen) EndFunc ;==> _MusPlusPlus #region ; conditionals Func _IsInstrument($sInstruction) Return StringRegExp($sInstruction, "(?i)(\A<[a-z \-_0-9]+>\z)") EndFunc ;==> _IsInstrument Func _IsKeySig($sInstruction) Return StringRegExp($sInstruction, "(\A[0-7][#b]\z)") EndFunc ;==> _IsKeySig Func _IsTimeSig($sInstruction) ; Requires accentuation / dynamics Return StringRegExp($sInstruction, "(\A\d+/(1|2|4|8|16|32|64)\z)") EndFunc ;==> _IsTimeSig Func _IsTempoMark($sInstruction) Return StringRegExp($sInstruction, "(\A[o\+;\-~\\\?]\.?=\d*\.?\d+\z)") EndFunc ;==> _IsTempoMark Func _IsAtTempo($sInstruction) Return $sInstruction = "@Tempo" ; not case sensitive EndFunc ;==> _IsAtTempo Func _IsSegno($sInstruction) Return $sInstruction = "$" EndFunc ;==> _IsSegno Func _IsBarLine($sInstruction) Return $sInstruction = "|" EndFunc ;==> _IsBarLine Func _IsStartRepeat($sInstruction) Return $sInstruction = "|:" EndFunc ;==> _IsStartRepeat Func _Is2ndTimeRound($sInstruction) Return StringRegExp($sInstruction, "(\A\d+,\z)") EndFunc ;==> _Is2ndTimeRound Func _IsTie($sInstruction) Return $sInstruction = "_" EndFunc ;==> _IsTie Func _IsStartTuplet($sInstruction) Return StringRegExp($sInstruction, "(\A\d*\(\z)") EndFunc ;==> _IsStartTuplet Func _IsNote($sNote) If StringRegExp($sNote, "(\A'*[A-G](#|b|bb|x|z)?'*\z)") Then Return 1 Return StringRegExp($sNote, "(\A[o\+;\-~\\\?\.]+('*[A-G](#|b|bb|x|z)?'*)?\z)") EndFunc ;==> _IsNote Func _IsEndTuplet($sInstruction) Return $sInstruction == ")" EndFunc ;==> _IsEndTuplet Func _IsEndRepeat($sInstruction) Return $sInstruction = ":|" EndFunc ;==> _IsEndRepeat Func _IsCoda($sInstruction) Return $sInstruction == "Q" EndFunc ;==> _IsCoda Func _IsDalSegno($sInstruction) Return $sInstruction == "DS" EndFunc ;==> _IsDalSegno Func _IsDaCapo($sInstruction) Return $sInstruction == "DC" EndFunc ;==> _IsDaCapo Func _IsFin($sInstruction) Return $sInstruction == "fin" EndFunc ;==> _IsFin Func _IsOctave($sInstruction) Return StringRegExp($sInstruction, "\A\{[0-8]\}\z") EndFunc ;==> _IsOctave Func _IsCurrentNote($sInstruction) Return StringRegExp($sInstruction, "\A\{[o+;=~\?]\.*\}\z") EndFunc ;==> _IsCurrentNote #endregion ;==> conditionals #region ; currently unsupported features Func _IsTechnique($sInstruction) ; Returns an integer - gliss is currently not supported Return StringInStr(" gliss pizz ", " " & $sInstruction & " ", 1) EndFunc ;==> _IsTechnique Func _IsBarRepeat($sInstruction) ; currently unsupported Return StringRegExp($sInstruction, "(\A%\d*\z)") EndFunc ;==> _IsBarRepeat Func _IsAccel($sInstruction) ; currently unsupported Return StringInStr(" accel rit ", " " & $sInstruction & " ", 1) EndFunc ;==> _IsAccel Func _IsDynamicMark($sInstruction) ; Returns an integer - currently unsupported Return StringInStr(" cres dim ppp pp /p mp mf /f ff fff ", " " & $sInstruction & " ", 1) EndFunc ;==> _IsDynamicMark #endregion ;==> currently unsupported features #region ; data requests Func _GetAccidental($aAccidentals, ByRef $sNote) Local $sAlpha = StringReplace($sNote, "'", "") $sNote = StringReplace($sNote, $sAlpha, $sAlpha & $aAccidentals[Asc($sAlpha) - 65], 0, 1) EndFunc ;==> _GetAccidental Func _GetKey($sKey) Local $iSign = 1 If StringInStr($sKey, "b", 1) Then $iSign = -1 Return StringRegExpReplace($sKey, "[#b]", "")*$iSign EndFunc ;==> _GetKey Func _GetQuartNoteBPM($sTempo) Local $aTempo = StringSplit($sTempo, "=", 2) Local $iNote = StringInStr("?\~-;+o", $aTempo[0]) -5 Return $aTempo[1]*2^$iNote EndFunc ;==> _GetQuartNoteBPM Func _GetCurrNote($sNote) Local $sCurrChr, $sRhythm = "" For $i = StringLen($sNote) To 1 Step -1 $sCurrChr = StringMid($sNote, $i, 1) $sRhythm = $sCurrChr & $sRhythm If StringInStr("o+;-~\?", $sCurrChr, 1) Then ExitLoop Next Return $sRhythm EndFunc ;==> _GetCurrNote Func _GetOctave($sNote) Local $iPos, $iOctave = 4 For $i = 65 To 71 $iPos = StringInStr($sNote, Chr($i), 1) If $iPos Then ExitLoop EndIf Next For $i = 1 To $iPos -1 If StringMid($sNote, $i, 1) = "'" Then $iOctave -= 1 Next For $i = $iPos +1 To StringLen($sNote) If StringMid($sNote, $i, 1) = "'" Then $iOctave += 1 Next Return $iOctave EndFunc ;==> _GetOctave Func _GetPitch($sName, $iKey = 0, $iOctave = 4) Local $iPitch, $sAlpha Select Case StringInStr($sName, "C", 1) $sAlpha = "C" $iPitch = 39 Case StringInStr($sName, "D", 1) $sAlpha = "D" $iPitch = 41 Case StringInStr($sName, "E", 1) $sAlpha = "E" $iPitch = 43 Case StringInStr($sName, "F", 1) $sAlpha = "F" $iPitch = 44 Case StringInStr($sName, "G", 1) $sAlpha = "G" $iPitch = 46 Case StringInStr($sName, "A", 1) $sAlpha = "A" $iPitch = 48 Case StringInStr($sName, "B", 1) $sAlpha = "B" $iPitch = 50 EndSelect Select Case StringInStr($sName, "bb", 1) $iPitch -= 2 Case StringInStr($sName, "b", 1) $iPitch -= 1 Case StringInStr($sName, "z", 1) $iPitch += 0 Case StringInStr($sName, "#", 1) $iPitch += 1 Case StringInStr($sName, "x", 1) $iPitch += 2 Case $iKey If $iKey > 0 Then If StringInStr(StringLeft("FCGDAEB", $iKey), $sAlpha) Then $iPitch += 1 Else If StringInStr(StringRight("FCGDAEB", -$iKey), $sAlpha) Then $iPitch -= 1 EndIf EndSelect $iOctave -= 4 $iPitch += $iOctave*12 If $iPitch < 0 Or $iPitch > 87 Then Return SetError (2, 0, "") ; Out of range pitch Return $iPitch ; values range from 0 to 87 EndFunc ;==> _GetPitch Func _GetDuration($sNote, $iTempo = 100, $iTuplet = 1) Local $sLen = StringLen($sNote) If Not $sLen Then Return Default If StringLeft($sNote, 1) = "." Then Return SetError(1, 0, 0) ; Syntax error - Dot not preceeded by a note value Local $iDuration = 0, $iDots = 0, $sCurrChr = "", $iID, $iNote = 0 For $i = 1 To $sLen $sCurrChr = StringMid($sNote, $i, 1) $iID = StringInStr("?\~-;+o.", $sCurrChr) -1 Switch $iID Case 0 To 6 $iDuration += $iNote $iNote = 6930 * 2^$iID Case 7 While $sCurrChr = "." $iDots += 1 $i += 1 $sCurrChr = StringMid($sNote, $i, 1) WEnd $iNote *= (2^($iDots +1) -1)/2^$iDots $i -= 1 $iDots = 0 EndSwitch Next $iDuration += $iNote If $iTuplet > 1 Then Switch $iTuplet Case 2, 4, 8, 16, 32, 64 ; In mus - only 2 and 4 appear, and then only in compound time $iDuration *= 3/2 ; it's the same result in all cases Case 3 ; triplets are the most common tuplet division $iDuration *= 2/3 Case 5 To 7 $iDuration *= 4/$iTuplet Case 9 To 15 ; In mus - tuplets greater than 12 almost never appear $iDuration *= 8/$iTuplet Case 17 To 31 $iDuration *= 16/$iTuplet Case 33 To 63 $iDuration *= 32/$iTuplet Case 65 To 127 $iDuration *= 64/$iTuplet Case Else Return SetError (2, 0, 0) ; Unsupported out of range tuplet value EndSwitch EndIf Return $iDuration*125/(231*$iTempo) EndFunc ;==> _GetDuration Func _GetInstrument($vInstrument) $vInstrument = StringRegExpReplace($vInstrument, "[<>]", "") Local $aMIDIInst[72][4] _ ; A selection of available MIDI imstruments = _ ; Name , ##,Mn,Mx [["pno" , 0, 0,87], _ ; Acoustic Grand Piano ... KEYBOARDS ["br pno" , 1, 0,87], _ ; Bright Piano ["e pno" , 2, 0,87], _ ; Electric Grand Piano ["h-t pno" , 3, 0,87], _ ; Honky-tonk piano ["hpsd" , 6, 0,87], _ ; Harpsichord ["clav" , 7, 0,87], _ ; Clavichord ["cel" , 8, 0,87], _ ; Celesta ["glock" , 9, 0,87], _ ; Glockenspiel ... PITCHED PERCUSSION ["mus box" , 10, 0,87], _ ; Music Box ["vib" , 11, 0,87], _ ; Vibraphone ["marim" , 12, 0,87], _ ; Marimba ["xyl" , 13, 0,87], _ ; Xylophone ["chimes" , 14, 0,87], _ ; Tubular Bells ["dulc" , 15, 0,87], _ ; Dulcimer ["ham org" , 16, 0,87], _ ; Drawbar Organ ... ORGAN ["perc org" , 17, 0,87], _ ; Percussive Organ ["org" , 19, 0,87], _ ; Church Organ ["harm" , 20, 0,87], _ ; Harmonium Reed Organ ["accord" , 21, 0,87], _ ; Accordion ["mouth org", 22, 0,87], _ ; Harmonica ["tango acc", 23, 0,87], _ ; Bandoneon ["gtr" , 24, 0,87], _ ; Classical Guitar ... GUITAR ["a gtr" , 25, 0,87], _ ; Accoustic Guitar ["jazz gtr" , 26, 0,87], _ ; Jazz Guitar ["e gtr" , 27, 0,87], _ ; Electric Guitar ["mut gtr" , 28, 0,87], _ ; Muted Electric Guitar ["fuzz gtr" , 30, 0,87], _ ; Distortion Guitar ["a bass" , 32, 0,87], _ ; Acoustic Bass ... BASS ["e bass" , 33, 0,87], _ ; Electric Bass ["bass" , 34, 0,87], _ ; Upright Bass ["f bass" , 35, 0,87], _ ; Fretless Bass ["sl bass" , 36, 0,87], _ ; Slap Bass ["vln" , 40, 0,87], _ ; Violin ... STRINGS ["vla" , 41, 0,87], _ ; Viola ["vc" , 42, 0,87], _ ; Cello ["db" , 43, 0,87], _ ; Double Bass ["hp" , 46, 0,87], _ ; Harp ["timp" , 47, 0,87], _ ; Timpani (perc) ["tpt" , 56, 0,87], _ ; Trumpet ... BRASS ["tbn" , 57, 0,87], _ ; Trombone ["tba" , 58, 0,87], _ ; Tuba ["mut tpt" , 59, 0,87], _ ; Muted Trumpet ["hn" , 60, 0,87], _ ; French Horn ["s sax" , 64, 0,87], _ ; Soprano Sax ... REED ["a sax" , 65, 0,87], _ ; Alto Sax ["sax" , 66, 0,87], _ ; Tenor Sax ["b sax" , 67, 0,87], _ ; Baritone Sax ["ob" , 68, 0,87], _ ; Oboe ["eng hn" , 69, 0,87], _ ; English Horn ["bsn" , 70, 0,87], _ ; Bassoon ["cl" , 71, 0,87], _ ; Clarinet ["picc" , 72, 0,87], _ ; Piccolo ... PIPE ["fl" , 73, 0,87], _ ; Flute ["rec" , 74, 0,87], _ ; Recorder ["pan" , 75, 0,87], _ ; Panpipes ["bottle" , 76, 0,87], _ ; Bottle ["shaku" , 77, 0,87], _ ; Shakuhachi ["whistle" , 78, 0,87], _ ; Whistle ["oc" , 79, 0,87], _ ; Ocarina ["sitar" ,104, 0,87], _ ; Sitar ... OTHER ["banjo" ,105, 0,87], _ ; Banjo ["shamisen" ,106, 0,87], _ ; Shamisen ["koto" ,107, 0,87], _ ; Koto ["kalimba" ,108, 0,87], _ ; Kalimba (perc) ["bagp" ,109, 0,87], _ ; Bagpipe ["fiddle" ,110, 0,87], _ ; Fiddle ["shanai" ,111, 0,87], _ ; Shanai (woodwind) ["bell" ,112, 0,87], _ ; Tinkle Bell ["st drum" ,114, 0,87], _ ; Steel Drums ["w bl" ,115, 0,87], _ ; Woodblock ["taiko" ,116, 0,87], _ ; Taiko Drum ["tom-t" ,117, 0,87]] ; Tom-tom For $i = 0 To 71 If $aMIDIInst[$i][0] = $vInstrument Then $vInstrument = $aMIDIInst[$i][1] ExitLoop EndIf Next $vInstrument = StringRegExpReplace($vInstrument, "[<>]", "") If StringRegExp($vInstrument, "[^\d]") Or $vInstrument < 0 Or $vInstrument > 127 Then Return SetError(1, 0, 0) ; returns Grand Piano Return $vInstrument ; values range from 0 to 117 EndFunc ;==> _GetInstrument #endregion ;==> data requests #region ; miscellaneous functions Func _InitialTidySource($sSource) If _IllegalDotCheck($sSource) Then Return SetError(1, 0, 0) $sSource = StringReplace($sSource, '"', "''") ; Helmholtz-Wilkinson octaves $sSource = StringReplace($sSource, '(', "( ") ; Add spaces after ( $sSource = StringReplace($sSource, ')', " ) ") ; Add spaces before and after ) $sSource = StringRegExpReplace($sSource, "(<\h+)", " <") ; Remove spaces after < $sSource = StringRegExpReplace($sSource, "(\h+>)", "> ") ; Remove spaces before > $sSource = StringReplace($sSource, '_', " _ ") ; Add spaces before and after underscore $sSource = StringReplace($sSource, '|:', "|: ") ; Add spaces after start repeats $sSource = StringReplace($sSource, ':|', " :|") ; Add spaces before end repeats $sSource = StringReplace($sSource, ':|:', ":||:") ; Convert double repeat marks _ $sSource = StringReplace($sSource, '|', " | ") ; Add spaces before and after bar lines $sSource = StringReplace($sSource, '| :', "|:") ; Restore start repeat marks $sSource = StringReplace($sSource, ': |', ":|") ; Restore end repeat marks $sSource = StringReplace($sSource, ' | | ', " || ") ; Restore double bar lines $sSource = StringRegExpReplace($sSource, "(<[\-\w]+)(\h+)(pno|box|org|acc|gtr|bass|tpt|sax|hn|drum|bl)", "$1" & "_" & "$3") $sSource = StringReplace(StringReplace($sSource, @CRLF, @LF), @CR, @LF) ; Replace all breaks with @LF $sSource = StringRegExpReplace($sSource, "(\n\h*)", @LF) ; Remove spaces after breaks $sSource = StringRegExpReplace($sSource, "[\n]{2,}", @LF & @LF) ; Remove duplicate empty lines $sSource = StringRegExpReplace($sSource, "(\A\n*)", "") ; Remove Preceeding breaks $sSource = StringRegExpReplace($sSource, "(\n*\z)", "") ; Remove Trailing breaks Return $sSource EndFunc ;==> _InitialTidySource Func _UpdateCurrentAttrib(ByRef $vCurrAttrib, ByRef $aVoices, $vNewAttrib, $iIndex, $sPadLeft = "", $sPadRight = " ") If $vCurrAttrib <> $vNewAttrib Then $vCurrAttrib = $vNewAttrib $aVoices[$iIndex] &= $sPadLeft & $vCurrAttrib & $sPadRight EndIf EndFunc ;==> _UpdateCurrentAttrib Func _ClearAccidentals(ByRef $aAccidentals) For $i = 0 To 6 $aAccidentals[$i] = "" Next EndFunc ;==> _ClearAccidentals Func _UpdateAccidentals(ByRef $aAccidentals, $sNote) $sNote = StringReplace($sNote, "'", "") Local $sAlpha = StringLeft($sNote, 1) $aAccidentals[Asc($sAlpha) - 65] = StringTrimLeft($sNote, 1) EndFunc ;==> _UpdateAccidentals Func _NoteSplit($sNote) Local $aNotePart[2] = ["", ""] $aNotePart[1] = StringRegExpReplace($sNote, "[o\+;\-~\\\?\.]+", "") ; Remove rhthmic values $aNotePart[0] = StringLeft($sNote, StringLen($sNote) - StringLen($aNotePart[1])) Return $aNotePart EndFunc ;==> _NoteSplit Func _IllegalDotCheck($sVoo) Return StringRegExp($sVoo, "(o\.{7}|\+\.{6}|;\.{5}|\-\.{4}|~\.{3}|\\\.\.|\?\.)") ; Warning - detected an unsupported number of dots after a note EndFunc ;==> _IllegalDotCheck #endregion ;==> miscellaneous functions #region ; MIDI functions ;======================================================= ;Retrieves a MIDI handle and Opens the Device ;Parameters(Optional) - Device ID, Window Callback, ; instance, flags ;Author : Eynstyne ;Library : Microsoft winmm.dll ;======================================================= Func _MidiOutOpen($devid = 0, $callback = 0, $instance = 0, $flags = 0) Local $ret = DllCall("winmm.dll", "long", "midiOutOpen", "handle*", 0, "int", $devid, "dword_ptr", $callback, "dword_ptr", $instance, "long", $flags) If @error Then Return SetError(@error,0,0) If $ret[0] Then Return SetError(-1,$ret[0],0) Return $ret[1] EndFunc ;==>_MidiOutOpen ;======================================================= ;Closes Midi Output/Input devices ;Parameters - MidiHandle ;Author : Eynstyne ;Library : Microsoft winmm.dll ;======================================================= Func _MidiOutClose ($hmidiout) Local $ret = DllCall("winmm.dll", "long", "midiOutClose", "handle", $hmidiout) If @error Then Return SetError(@error,0,0) If $ret[0] Then Return SetError(-1,$ret[0],0) Return $ret[0] EndFunc ;==> _MidiOutClose ;======================================================= ;Gets the Mixer Volume for MIDI ;Parameters - None ;Author : Eynstyne ;Library : Microsoft winmm.dll ;======================================================= Func _MidiOutGetVolume ($devid = 0) Local $ret = DllCall("winmm.dll", "long", "midiOutGetVolume", "handle", $devid, "dword*",0) If @error Then Return SetError(@error,0,0) If $ret[0] Then Return SetError(-1,$ret[0],0) Return $ret[2] EndFunc ;==> _MidiOutGetVolume ;======================================================= ;Sets the Mixer Volume for MIDI ;Parameters - Volume (0 - 65535) ;Author : Eynstyne ;Library : Microsoft winmm.dll ;======================================================= Func _MidiOutSetVolume($iVolume = 65535, $devid = 0) Local $iMixVolume=BitAND($iVolume,0xFFFF)+BitShift(BitAND($iVolume,0xFFFF),-16) ; From Ascend4nt Local $ret = DllCall("winmm.dll", "long", "midiOutSetVolume", "handle", $devid, "int", $iMixVolume) If @error Then Return SetError(@error,0,0) If $ret[0] Then Return SetError(-1,$ret[0],0) Return $ret[0] EndFunc ;==> _MidiOutSetVolume ;======================================================= ;MIDI Message Send Function ;Parameters - Message as Hexcode or Constant ;Author : Eynstyne ;Library : Microsoft winmm.dll ;======================================================= Func _MidiOutShortMsg($hmidiout, $msg) Local $ret = DllCall("winmm.dll", "long", "midiOutShortMsg", "handle", $hmidiout, "long", $msg) If @error Then Return SetError(@error,0,0) If $ret[0] Then Return SetError(-1,$ret[0],0) Return $ret[0] EndFunc ;==> _MidiOutShortMsg #endregion ;==> MIDI functions #region ; functions ripped from arrayf.au3 and stringf.au3 ; #FUNCTION# ==================================================================================================================== ; Name...........: _ArraySortByNumber ; Description ...: Sorts a 1D array numerically ascending. ; Syntax.........: _ArraySortByNumber(ByRef $avArray [, $bVulgarFrac = False]) ; Parameters ....: $avArray - [ByRef] The array to sort ; $bVulgarFrac - [Optional] If set to True, vulgar fractions will be also be sorted numerically ; Return values .: Success - Returns 1 ; Failure - Returns zero and sets @error to the following values: ; |@error = 1 : $avArray is not a one dimensional array ; Author ........: czardas ; Modified.......: ; Remarks .......: The array is sorted first by numbers and then by strings. ; Related .......: _ArraySort, _ArraySortByLen ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _ArraySortByNumber(ByRef $avArray, $bVulgarFrac = False) If Not IsArray($avArray) Or UBound($avArray, 0) > 1 Then Return SetError(1, 0, 0) Local $iBound = UBound($avArray) -1 Local $aTemp[$iBound +1][2] For $i = 0 To $iBound $aTemp[$i][0] = $avArray[$i] If _StringIsNumber($avArray[$i], $bVulgarFrac) Then $aTemp[$i][1] = Execute($avArray[$i]) Else $aTemp[$i][1] = "z" & $avArray[$i] EndIf Next _ArraySort($aTemp, 0, 0, 0, 1) For $i = 0 To $iBound $avArray[$i] = $aTemp[$i][0] Next Return 1 EndFunc ;==> _ArraySortByNumber ; #FUNCTION# ==================================================================================================================== ; Name...........: _StringIsNumber ; Description ...: Checks whether a string is a number as recognised by the AutoIt interpreter ; Syntax.........: _StringIsNumber($sString [, $bVulgarFrac]) ; Parameters ....: $sString - The string to test ; $bVulgarFrac - [Optional] if set to True, vulgar fractions will also return True ; Return values .: True or False ; Author ........: czardas ; Remarks .......: Returns True for integers, floats, hexadecimal and scientific notation. ; Related .......: StringIsDigit, StringIsFloat, StringIsInt, StringIsXDigit ; Link ..........: ; Example .......: MsgBox(0, "1.2e-300 is a number", _StringIsNumber("1.2e-300")) ; =============================================================================================================================== Func _StringIsNumber($sString, $bVulgarFrac = False) Local $bReturn = False If StringIsInt($sString) Or StringIsFloat($sString) Then $bReturn = True ; string is integer or float ElseIf StringRegExp($sString, "(?i)(\A[\+\-]?0x[A-F\d]+\z)") Then $bReturn = True ; string is hexadecimal integer ElseIf StringRegExp($sString, "(?i)(\A[\+\-]?\d*\.?\d+e[\+\-]?\d+\z)") Then $bReturn = True ; exponential (or scientific notation) ElseIf $bVulgarFrac And StringRegExp($sString, "(\A[\+\-]?\d+/\d+\z)") Then $bReturn = True ; string is a vulgar fraction EndIf Return $bReturn EndFunc ; _StringIsNumber #endregion ;==> functions ripped from arrayf.au3 and stringf.au3 ; I have made some small improvements to the current interpreter. I have tested all the features included in the language, and there are some small issues which still need addressing - things I haven't mentioned. Cleaning up the code for the interpreter is next on the agenda. I will also add more simple music examples for beginners to study. Enjoy. Edited June 16, 2013 by czardas operator64 ArrayWorkshop
czardas Posted July 29, 2013 Author Posted July 29, 2013 (edited) In view of the recent updates to the midi thread, this project will undergo a major overhaul. Because I'm so busy with commitments, the changes will have to wait. I advise caution when using separate endings in repeat sections with the current version. Bad syntax with this feature can cause infinite looping. I need to fix this with error handling. In the mean time here's one way the current version of mus++ can be compressed by removing as many symbols as possible and laying out each voice in a single line without breaks. Perhaps you will like it, although it becomes unreadable. ; _MusPlusPlus( _ ; Fur Elise " <pno> ;=132 |: -E' D# $ E D E 'B' Dz' C ;'A' - C E A ;B - E G# B ;C' - 'E' E' D# E D E 'B' Dz' C ;'A' - C E A ;B - E C' 'B' 1, +A :|2, ;A - B C' D |: ;-E 'Gz' F' E ;-D 'F' E' D ;-C 'E' D' C ;'B'" & _ " +;- D#' -E' D E D# E D E D E D E 'B' Dz' C ;'A' - C E A ;B - E G# B ;C' - 'E' E' D# E D E 'B' Dz' C ;'A' - C E A ;B - E C' 'B' Q 1, ;A - B C' D :|2, ;A 5(+ ~F A) +C' -~F E ;E D -~Bb A -A G F E D" & _ " C ;'Bb' 5(A ~B) A G A B +C' -D D# | ;-E E F 'A' ;.C \D C 'B' C' -~D 'B' |: ~C' ~ 'G' ~ A ~ B ~ C' ~ D ~ E G C' 'B' A G F E D G F D :| E F E D# E 'B' E' D E 'B' E' D ;-E 'B' E' D ;-E 'B' E' D E D" & _ " E D E D |: E D# E 'B' Dz' C ;'A' - C E A ;B - E G# B ;C' - 'E' E' D# E D E 'B' Dz' C ;'A' - C E A ;B - E C' 'B' 1, ;A - B C' D ;-E 'Gz' F' E ;-D 'F' E' D ;-C 'E' D' C ;'B' + ;- D#' -E D E D# E D" & _ " E D :|2, ;A + +.C#' +D -E F +F ;F +.E +D -Cz 'B' +A ;A ;A C' 'B' +.A +.C#' +D -E F +F ;F +.F +Eb -D Cz +'Bb' ;A +G# ;G | +A ; B + (-'A 'C' E A C' E D C 'B' A C' E A C'' E D C B' 'A' C' E A C'' E" & _ " D C B' Bb A Ab G Gb F E Eb D|Db'' C B Bb A Ab G Gb F) DS Q +A" & @CR & " <pno> ;=132 |: ; $ ooooo; 1, + :|2, +. |: oo-- ''E 'E 'E' E E' 'E' E' E E'' oooooo;. Q 1, +. :|2, ;- 'E' F E o.- E - E - E" & _ " ooo |: ~ G' ~ G ~ G ~ G ~ G ~ G +. :| ooo |: ooooo; 1, ooo -''E 'E 'E' E E' 'E' E' E E'' -o :|2, +. 'Bb' +A -C#' D +D ;D +.Cz +. +'F#' o+. B +A -C#' D +D ;D +.D +. +'Fz' ;F +F ;F +E ; E oooo; DS" & _ " Q +" & @CR & " <pno> ;=132 |: ; $ ooooo; 1, + :|2, +. |: ooooooooo.. Q 1, +. :|2, ;- 'C' C C o.. -'Bb - B oo- 'D' -- E - E - E |: ;- G G G ;G + :| ooo |: ooooo; 1, ooooo; :|2, +. G +F ; +G# ;G +.A" & _ " +F -E D +C ;C ;C E D +.C Gz +F o.. +G -F Eb +D ;D +D ;D +C ; D o ;Ez E ; E E ; E E o; DS Q +C" & @CR & " <pno> ;=132 |: ; $ ooooo; 1, + :|2, +. |: ooooooooo.. Q 1, +. :|2, +- 'Bb o.. -G - G -ooo" & _ " |: ;'E' ;- E ;E 'A 'B :| B oo.. |: ooooo; 1, ooooo; :|2, +. E' oo-- ''A |: 15, A :| G# G ''A -+ +.'E' ooooo; 'G o ;'C' C ; C C ; C C o; DS Q +''A" & @CR & " <pno> ;=132 |: ; $ +-- ''A 'E A ;-" & _ " ''E 'E G# ;- ''A 'E A o- ''A 'E A ;- ''E 'E G# ;- 1, ''A 'E A - :|2, ''A 'E A ;- |: 'C G 'C' ;- ''G 'G B ;- ''A 'E A ooo;- ''A 'E A ;- ''E 'E G# ;- ''A 'E A o- ''A 'E A ;- ''E 'E G# ;- Q 1, ''A 'E" & _ " A ;- :|2, ''A 'E A Bb A G F A 'C' 'A 'C' 'A F Bb 'D' 'B 'D' 'B F - F - F - F A 'C' 'A 'C' 'A F A 'C' 'A 'C' 'A E A 'C' 'A D F G - G - G - |: ;'C' - F E D ;C 'F G :| ;G# oo+; |: +-- ''A 'E A ;- ''E" & _ " 'E G# ;- ''A 'E A o- ''A 'E A ;- ''E 'E G ;- 1, ''A 'E A ;- 'C Gz 'C' ;- ''G 'G B ;- ''A 'E A oo+- :|: 30, ''A :|: 16, ''D :|''E E '''A|: 23, ''A :|: 18, ''Bb :| ''Bz B B B B B +'C ; E + ;'''A ;" & _ " 'A A ; A A ; A A o; DS Q +'''A") ; I used a hack 5(A ~ to create grace notes. This is a neat little trick giving you a lot of control. There are so many things to consider and flexibility is paramount. Haha the editor turned my grace note into a smiley. ^^ Edited July 30, 2013 by czardas operator64 ArrayWorkshop
Ascend4nt Posted July 29, 2013 Posted July 29, 2013 czardas, did you invent this mus++ language? If so, that's pretty impressive! As is the interpreter.. very cool indeed My contributions: Performance Counters in Windows - Measure CPU, Disk, Network etc Performance | Network Interface Info, Statistics, and Traffic | CPU Multi-Processor Usage w/o Performance Counters | Disk and Device Read/Write Statistics | Atom Table Functions | Process, Thread, & DLL Functions UDFs | Process CPU Usage Trackers | PE File Overlay Extraction | A3X Script Extract | File + Process Imports/Exports Information | Windows Desktop Dimmer Shade | Spotlight + Focus GUI - Highlight and Dim for Eyestrain Relief | CrossHairs (FullScreen) | Rubber-Band Boxes using GUI's (_GUIBox) | GUI Fun! | IE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) | Magnifier (Vista+) Functions UDF | _DLLStructDisplay (Debug!) | _EnumChildWindows (controls etc) | _FileFindEx | _ClipGetHTML | _ClipPutHTML + ClipPutHyperlink | _FileGetShortcutEx | _FilePropertiesDialog | I/O Port Functions | File(s) Drag & Drop | _RunWithReducedPrivileges | _ShellExecuteWithReducedPrivileges | _WinAPI_GetSystemInfo | dotNETGetVersions | Drive(s) Power Status | _WinGetDesktopHandle | _StringParseParameters | Screensaver, Sleep, Desktop Lock Disable | Full-Screen Crash Recovery Wrappers/Modifications of others' contributions: _DOSWildcardsToPCRegEx (original code: RobSaunder's) | WinGetAltTabWinList (original: Authenticity) UDF's added support/programming to: _ExplorerWinGetSelectedItems | MIDIEx UDF (original code: eynstyne) (All personal code/wrappers centrally located at Ascend4nt's AutoIT Code)
czardas Posted July 29, 2013 Author Posted July 29, 2013 (edited) Thanks Ascend4nt - your excellent examples in the midi thread have been very helpful to me, and yes I created this to simplify several tasks. I introduced some features which are perhaps more suitable to programming, but the majority of the syntax bears a direct relationship to features existing in written music - making it easy to edit (once you get used to it): because the script uses lots of abstraction compaired to raw midi. I'll soon be using it as an integral part of the code behind some programs to aid music students (including myself ). Edited July 29, 2013 by czardas operator64 ArrayWorkshop
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now