Kara-Moon Forum
March 28, 2024, 08:07:33 PM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News: You can go back to the main site here: Kara-Moon site
 
   Home   Help Search Login Register  
Pages: [1]
  Print  
Author Topic: Subroutines  (Read 5297 times)
sciurius
Sr. Member
****
Posts: 443



« on: May 18, 2020, 07:41:49 PM »

Reflecting on the 'Truncate and Subroutines'...

Code:
Set Tempo 120

Begin Plectrum
    Voice       NylonGuitar
End

/**************** Plectrum patterns ****************/

Begin Plectrum Define
      G4E       1.0   0   6:90 5-4:0;   \
              1.5   0   3-1:70;       \
        2.0   0   4:70;         \
        2.5   0   3-1:70;       \
        3.0   0   6:80;         \
        3.5   0   3-1:70;       \
        4.0   0   4:70;         \
        4.5   0   3-1:70
 
      G4A 1.0   0   5:90 6:0 4:0; \
      1.5   0   3-1:70;       \
2.0   0   4:70;         \
2.5   0   3-1:70;       \
3.0   0   5:80;         \
3.5   0   3-1:70;       \
4.0   0   4:70;         \
4.5   0   3-1:70
 
      G4D 1.0   0   4:90 6:0 5:0; \
      1.5   0   3-1:70;       \
2.0   0   5:70;         \
2.5   0   3-1:70;       \
3.0   0   4:80;         \
3.5   0   3-1:70;       \
4.0   0   5:70;         \
4.5   0   3-1:70
End

DefCall G4E Chords
Plectrum Sequence G4E
  1    $Chords
EndDefCall
Set G4E Call G4E

DefCall G4A Chords
Plectrum Sequence G4A
  1    $Chords
EndDefCall
Set G4A Call G4A

DefCall G4D Chords
Plectrum Sequence G4D
  1    $Chords
EndDefCall
Set G4D Call G4D

/**************** Song parts ****************/

$G4A   Am * 2
$G4D   Dm * 2
$G4E   E  * 2
$G4A   Am * 2

Finally a way to set a pattern and chord in one line.
Logged
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #1 on: May 19, 2020, 02:12:06 AM »

I really like subroutines ... and we should try to used them more!

The only problem with them is that you can't have a variable number or arguments ... so in your case, you'd need a different sub for "Am", "Am / Gm /", etc. You could use macros to hold the chords and pass that to the subroutine, but that might be silly.

I'm going to have to play with this and see if I can get it work. Maybe it already does ... way too much code here for me to remember what/why I've written.
Logged

My online life: http://www.mellowood.ca
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #2 on: May 19, 2020, 03:29:53 AM »

What you think about introducing a grouping option? I'm thinking the ()s not used at this point ... so, we could say that stuff inside them are to be assigned to a subroutine arg. So, my earlier example:

Code:
DefCall To54 chord
  Truncate 1
  $Chord
  $Chord
EndDefCall

would work fine using:

Code:
Call To54 (Am / Gm)   /// 3 chords to CHORD
Call To54 F                ///  1 chord to CHORD


Just a matter of taking the stuff in () and assigning it to "chord" as one chunk. Just now (and it's getting late) I don't see why this wouldn't work.

Comments?
Logged

My online life: http://www.mellowood.ca
sciurius
Sr. Member
****
Posts: 443



« Reply #3 on: May 19, 2020, 08:48:01 AM »

Quote
I really like subroutines ... and we should try to used them more!

Most certainly. We're programmers, after all Smiley .

Quote
The only problem with them is that you can't have a variable number or arguments ...

I think we're hitting a very low-level design issue of MMA: the parser.

Currently, source lines are split into whitespace separated items (let's call them 'words') immedeately after reading. This means you cannot write things like (in a sequence)
  1.5   0   3-1:$LOUD
since the macro needs to be a word. You cannot write (in the .mmarc)
  SetLibPath My Documents/mma
unless you want your stuff in the folders "My" and "Documents/mma".

Likewise, (Am G C) are three words, "(Am", "G", and "C)". You can artificially apply some heuristics on leading and trailing parens but it is clumsy and error prone. The same goes for good old strings, e.g. print "A             B" will print two words, ""A" and "B"" instead of the (more logical) string "A             B".

A token based parser would be much better. I did some experiments but unfortunately (or maybe fortunately) I lost them... Using a tokenizing parser would have a drastic impact and probably break a lot of songs...


Logged
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #4 on: May 19, 2020, 04:17:14 PM »

Yup.

If I were to start all over again I'd make different decisions. Unfortunately, MMA was really designed to be a very simple, super metronome and then morphed into the monster we now have. Still, it works pretty well. After all, how often do you need to print strings with quotation marks when creating a midi file? And that was then and we're now here in the present Smiley

But, adding () to the subroutine code should be painless and useful. As always, give me a day or so.
Logged

My online life: http://www.mellowood.ca
sciurius
Sr. Member
****
Posts: 443



« Reply #5 on: May 20, 2020, 06:26:15 AM »

I don't see the problem with multiple arguments. When called with several arguments you can slice:

 DefCall MySub Arg
    print Arg = $Arg         // all args
    print Arg 1 = $ARG[0]    // first word of arg
    print Arg 2 = $ARG[1]    // second word of arg
    ...


Using multiple variables would be nice, though:

 DefCall MySub Arg1 Arg2 Arg3
     print Arg 1 = $Arg1
     print Arg 2 = $Arg2
     ...


Another option would be a special function, e.g.

  $_SUBARG(0)            // number of words in arg
  $_SUBARG(1)            // 1st word of arg
  $_SUBARG(2)            // 2nd word
  ...


This would allow looping over the arguments.
« Last Edit: May 20, 2020, 06:46:37 AM by sciurius » Logged
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #6 on: May 20, 2020, 04:14:14 PM »

I don't see the problem with multiple arguments. When called with several arguments you can slice:

 DefCall MySub Arg
    print Arg = $Arg         // all args
    print Arg 1 = $ARG[0]    // first word of arg
    print Arg 2 = $ARG[1]    // second word of arg
    ...



Only problem here is that you need to know in advance how many args there are Smiley Looking (just looking!) at () is on the top of my pile of things to do.
Logged

My online life: http://www.mellowood.ca
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #7 on: May 20, 2020, 04:33:42 PM »

Bugger, here I coded the [] code and then I forget about it Smiley So, for my original code the following works:

Code:

DefCall To54 chord
  print $Chord[:]
  Truncate 1
  $Chord[0]
  $Chord
EndDefCall

Call To54  Bm Cm F G
Call To54 G
Call To54 Dm
Call To54 C

Neato Smiley Maybe I don't need to look at () after all (which would make my life much simpler!).
Logged

My online life: http://www.mellowood.ca
sciurius
Sr. Member
****
Posts: 443



« Reply #8 on: May 20, 2020, 05:33:29 PM »

Given that slicing tries to follow python syntax it should be noted that $var[] should be invalid.

With the attached very simple patch to MMA/macro.py $var[] now returns the number of words in $var. Do we need more?


* macro-slice.patch.txt (2.23 KB - downloaded 219 times.)
Logged
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #9 on: May 21, 2020, 01:43:42 AM »

Actually, this is quite brilliant. We can now do something like:

Code:

DefCall To54 chord
  set numargs $( $Chord[] )
  Truncate 1
  if gt $numargs  1
       $Chord[0]
  else
      $chord
  endif
  $Chord
EndDefCall

Call To54  Bm Cm F G
Call To54 G
Call To54 Dm
Call To54 C


Of course, it's no better than my earlier example and the if/then is completely redundant ... but taking actions inside a subroutine based on the number of arguments could be a lot of fun. I think there could be lots of uses for this in the future! I will post a new developer release in a few days ... hopefully, a new mainstream release will be "real soon now" as well.

Thanks so much!
Logged

My online life: http://www.mellowood.ca
sciurius
Sr. Member
****
Posts: 443



« Reply #10 on: May 21, 2020, 06:23:34 AM »

  set numargs $( $Chord[] )

Why not

  set numargs $Chord[]

Logged
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #11 on: May 21, 2020, 04:19:40 PM »

Why not

  set numargs $Chord[]


Aw, that'd be way to simple Smiley

Of course, the other way around this is to add len() to the permitted ops in safe_eval ... but, I think leaving it as is will be just fine.
Logged

My online life: http://www.mellowood.ca
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #12 on: May 21, 2020, 05:38:00 PM »

What is really nutty is that one really doesn't need to know the number of args for my little subrouting at all. Using:

 
Code:
DefCall To54 chord
  Truncate 1   
  $Chord[:1]
  $Chord
EndDefCall

Call To54  Bm Cm F G
Call To54 G
Call To54 / / B F

Works just fine with any number of chords passed Smiley
Logged

My online life: http://www.mellowood.ca
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #13 on: June 19, 2020, 02:22:42 AM »

I was adding this code to the "egs" directory for MMA and caught some faults Smiley This bit will work much better:

Code:
DefCall To54 chord
  Truncate 1
  $Chord[:1]
  Set Chord $Chord[1:]
  Set Length $Chord[]
  If Eq $Length 0
     Set Chord /
  Endif
  $Chord
EndDefCall


The only issue with this bit of code is that if you decide to use the "@" modifier to place the offsets of chords it will not work.

I really hope this bit of code and discussion helps someone in the future.
Logged

My online life: http://www.mellowood.ca
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.057 seconds with 20 queries.