Kara-Moon Forum
March 29, 2024, 08:12:22 AM *
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] 2
  Print  
Author Topic: code for patPlectrum.py: A realistic guitar sound  (Read 24266 times)
louisjb
Jr. Member
*
Posts: 16


« on: December 29, 2009, 02:32:44 PM »

Hi Bob + others,

Attached is the source code for a new Plectrum patten that I have knocked up. It simulates any type of instrument that you would play with a plectrum eg a guitar or mandolin etc. But I have focused on getting a realistic guitar sound. (Listen to the attached midi so you can judge for your self.)

first would choose the instruments by setting the tuning for each string which also defines the number of strings on the instrument.

     Tunning     e-- a-- d- g- b- e   // A guitar with six strings
     Tunning     g-- d- a- e          // A four string tenor Banjo

You also decide whether you want a capo by adding.

     Capo        5                    // The capo is on the fifth fret.

{NOTE: the Tunning and Capo do not work yet in the attached code}

Then you would define you strumming pattern as follows
Code:
Begin Plectrum-Strumming
    Voice       NylonGuitar
    Octave      4
    Volume      m
    Sequence { \
            1.0   +5     120 120 120 120 120 100; \
            2.0   +5      90  80  80  80  80  80; \
            2.5   -5       -   -  50  50  50  50; \
            3.0   +5      90  80  80  80  80  80; \
            3.5   -5       -   -  50  50  50  50; \
            4.0   +5      90  80  80  80  80  80; \
            4.5   -5       -   -  50  50  50  50; \
    }
End

the first number defines the beat offset, the +5 defines a downward strum with a gap of 5 ticks. -5 denotes an upward strum. The next six numbers are the velocity for each string, put a zero to mute that string and the - means skip that string (i.e. leave it vibrating with the previous note). NOTE: there are no note durations defined, like a real guitar the notes will keep ringing out until ether string is muted (use a velocity value of zero) or when a new note is played on that string.

You can also define finger picking pattens here is an example

Code:
Begin Plectrum-FingerPicking
    Voice       NylonGuitar
    Octave      4
    Volume      m
//  Tunning     e-- a-- d- g- b- e   // A guitar
//  Tunning     g-- d- a- e          // A four string tenor Banjo
//  Capo        0                    // The fret number of the capo
    Sequence { \
            1.0    0       - 100   -   -  90   -; \
            1.5    0       -   -   -  90   -   -; \
            2.0    0       -   -   90  -  90   -; \
            2.5    0       -   -   -  90   -   -; \
            3.0    0       -   -   -   -   -  90; \
            3.5    0       -   -   -   -  90   -; \
            4.0    0       -   -   -   90  -   -; \
            4.5    0       -   -   90  -   -   -; \
    }
End


This is alpha code at the moment as it has not been fully integrated in with MMA (assuming Bob accepts this patch)


Louis

* guitarPlectrum.mid (1.47 KB - downloaded 455 times.)
* guitarPlectrum.mma (1.66 KB - downloaded 474 times.)
* patPelctrum.zip (9.06 KB - downloaded 429 times.)
Logged
folderol
Kara-Moon Master
****
Posts: 5296

Who? Me?


WWW
« Reply #1 on: December 29, 2009, 03:52:13 PM »

Very impressive work. You clearly have put a lot of thought into this Cool

Wow! Just made a discovery wOO

That example MIDI  works very well with something quite different


* HandBells.ogg (383.28 KB - downloaded 478 times.)
« Last Edit: December 29, 2009, 04:12:31 PM by folderol » Logged

If you have a poem, I have a tune, and we exchange these, we can both have a poem, a tune, and a song.
- Will
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #2 on: December 29, 2009, 04:25:50 PM »

Ahh ... you just wanted to point out to the world that the author of MMA doesn't play a guitar!

Thanks so much Smiley

This is a nice bit of work. It will be accepted into MMA. But, a few comments/questions first:

 - Is the change to midi.py really needed or could it be done with the existing code. I had a QUICK look and don't see why yet another function is needed.

 - I assume that there are some tests outstanding where MMA does type (ie, CHORD, APREGGIO, etc) testing which need to be done. I don't think this is major since most of the paranoia is "is this a DRUM". The last time I added a track type was with ARIA and I don't recall anything big biting me.

- do you think a new type is needed? Or could CHORD be modified? Probably easiest to do it with a new type, but I wondering?Huh

- I suppose the docs are my problem Smiley

Seriously, lets do this!

Thanks.
Logged

My online life: http://www.mellowood.ca
louisjb
Jr. Member
*
Posts: 16


« Reply #3 on: December 29, 2009, 06:27:40 PM »

Hi Bob,

I look at trying to get what I wanted with CHORD first but I hit a problem with strum direction was either UP or DOWN or BOTH but BOTH _always_ alternated. I wanted a "down down up down up down" pattern. Also I could not find out a way make CHORD to play all six notes of a chord like on a guitar (and then just the top four strings of an up strum). CHORD only seemed to want to play only 3 notes of the chord.

I read carefully the thread "Acoustic guitar style"  on this forum. The resulting mma looked very complicated. involving defining two instruments. I wanted something that was very easy to use and behaved exactly like a real guitar for example a Gmaj is g-- b-- d- g- b-  g on a guitar and not g-- b-- d- g- b-  d.

The other difficulty was CHORD needed the note duration for every note involving a lot of very complicated maths. This brings me on the reason for adding the method addNoteOnToTrack to midi.py.
I do not know the duration of the note until the next chord is played (and if that note is not plucked or muted it could be even longer before the duration is known). There where two choices either add addNoteOnToTrack to midi.py or alternatively delay sending the note pair until the duration is known. But this would involve messing with Beatadjust because the notepair is sent late.

There is still some issues with the code that I do not know how to fix. no note offs are send when changing to a different groove or at the end of the piece. patPlectrum endAllVibrations should be called to do this.


I also have a another thought about the chord syntax could be changed to accept barre chords perhaps "^5Gmaj" would play a barre Gmaj chord on the 5th fret, ie the chord would be raised by five semitones. So "^12Gmaj" would be identical to "+Gmaj". Negative fret number could also be allowed ^-5Gmaj which would be impossible on a real guitar. To do this you need to set the value barreChordFretNo to patPlectrum fretboardNote

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


WWW
« Reply #4 on: December 29, 2009, 07:25:46 PM »

Hi Bob,

I look at trying to get what I wanted with CHORD first but I hit a problem with strum direction was either UP or DOWN or BOTH but BOTH _always_ alternated. I wanted a "down down up down up down" pattern. Also I could not find out a way make CHORD to play all six notes of a chord like on a guitar (and then just the top four strings of an up strum). CHORD only seemed to want to play only 3 notes of the chord.


Good points.

CHORD plays the notes in the current chord. So, if it's a triad (ie C,
D, Em, etc) it plays 3 notes. A 7th chord will play 4 notes, etc. But,
you are correct saying that this is a problem.

As far as up/down. You could define a longer sequence (ie, 8 bar
sequence). Then set the pattern like:

           Direction Down Down Up Down Down Up Down Up

Quote

I read carefully the thread "Acoustic guitar style"  on this forum. The resulting mma looked very complicated. involving defining two instruments. I wanted something that was very easy to use and behaved exactly like a real guitar for example a Gmaj is g-- b-- d- g- b-  g on a guitar and not g-- b-- d- g- b-  d.

Yes, I agree.

Quote
The other difficulty was CHORD needed the note duration for every note involving a lot of very complicated maths. This brings me on the reason for adding the method addNoteOnToTrack to midi.py.
I do not know the duration of the note until the next chord is played (and if that note is not plucked or muted it could be even longer before the duration is known). There where two choices either add addNoteOnToTrack to midi.py or alternatively delay sending the note pair until the duration is known. But this would involve messing with Beatadjust because the notepair is sent late.

Just looking quickly at the code ... am I right that the notes are
turned off the next time though the playbar code (ie, the next
beat/chord)? I avoided this with addPairToTrack() ... you are right
that prediction is hard and just waiting around for the next strum is
much easier.



Quote
There is still some issues with the code that I do not know how to
fix. no note offs are send when changing to a different groove or at
the end of the piece. patPlectrum endAllVibrations should be called to
do this.

I'll have to think a bit about the eof of file and groove change
problem. I'd like to think they can be handled at the same time, but I
don't think so. For now, I'm thinking that some special flags need to
be set:

   - for the eof of file. You could do something in main.py, similar
   to the code at line 296. Or, change doMidiClear() to check the new
   track-type. That might be easiest:

            if self.type == ... turn off notes

   - for the groove change? Not sure without tracing a bunch of
   code. But, similar I'd think?

Quote
I also have a another thought about the chord syntax could be changed to accept barre chords perhaps "^5Gmaj" would play a barre Gmaj chord on the 5th fret, ie the chord would be raised by five semitones. So "^12Gmaj" would be identical to "+Gmaj". Negative fret number could also be allowed ^-5Gmaj which would be impossible on a real guitar. To do this you need to set the value barreChordFretNo to patPlectrum fretboardNote

Louis

What happens to "other" tracks? It was my thought at one time to have
the ability to set differnt chords for different tracks. Still not
sure if this would be a silly thing, and needlessly complicated.

But, here's another thought: if you expand PLECTRUM a little bit could
we combine the cappo and barre? So, using a silly example, we could
have a data line:

        C / Gm

and above that a special plectrum line:

       PLECTRUM-V1  barre 3

Now, this would apply to all the chords, forever.

So, to effect just the 3rd/4th beat:

     PLECTRUM-V1  barre 0,0,3,4

or, you could even set this for patterns:

    PLECTRUM-V1  barre 0  0  4  5

And, then when you want "normal"

     PLECTRUM-V1 barre 0

Note the difference between 0,0,4,0 and 0 0 4 0 !

Also, I'm not excited about the terms PLECTRUM or BARRE. Is there
something better?Huh If not, we'll stick with this.

I'll let you work a bit more at your end. Then we'll try to do a merge
into my main code. Then a beta release.

Best,
Logged

My online life: http://www.mellowood.ca
louisjb
Jr. Member
*
Posts: 16


« Reply #5 on: December 30, 2009, 11:24:59 PM »

Hi Bob and others,

Just a quick note as I was out today and I will be away all of tomorrow. I'll reply in detail in the new year.

By the way I think permanent barre chord effects should be referred to as CAPO not BARRE.

folderol I really enjoyed the HandBells.ogg.

Louis
Logged
louisjb
Jr. Member
*
Posts: 16


« Reply #6 on: January 01, 2010, 03:47:43 PM »

Ok Bob,

I have done a bit more work on the PLECTRUM pattern and integrated it with code from mma-bin-1.5b. To try it out unzip the attached MMA-1.5c-dev1.zip file over the files in the MMA directory.

Quote
Also, I'm not excited about the terms PLECTRUM or BARRE. Is there
something better?

BARRE is the correct term for a barre chord see http://en.wikipedia.org/wiki/Barre_chord

But I was not suggesting adding BARRE as a key word only TUNNING and CAPO  but lets deal with my ideas for barre chords later.

Regarding the name PLECTRUM I considered the name GUITAR but that was no good as I also wanted it work with deferent types of string instruments like Lute, Mandolin, Banjo. I considered STRINGS but that was associated with violins. Other ideas were STRUM (you already use that) STRUMMER, PICKING, PLUCKING. Can you think of a better name? I now quite like the name PLECTRUM as it associated with the Guitar and Banjo etc. And you can talk about PLECTRUM patterns Smiley.

The most pressing problem is to call patPlectrum.closeGroove whenever that groove stops playing which will add note offs for all the outstanding notes. Adding closeGroove to the base class PC would be a good idea. I have a quick look at your code to try and implement this call but I really need your help with this. Basically we need to store the currently playing groove in a variable somewhere and whenever that currently playing groove is about to change to a new groove then to call pat.closeGroove() for the current groove just before it is replaced by the new groove.

Finally I would like to add the new keywords TUNING and CAPO which would call patPlectrum.setTuning() and patPlectrum.setCapo(). We really need noteNameToMidiValue("e--") method somewhere, that can be called from SetTunning. Again I really need your help with this one.

Code:
Begin Plectrum-FingerPicking
    Voice       NylonGuitar
    Octave      4
    Volume      m
    Tunning     e-- a-- d- g- b- e   // A guitar
   //Tunning     g-- d- a- e          // A four string tenor Banjo
    Capo        5                    // The fret number of the capo

And very finally I have changed mma.py as follows.

Code:
if platform == 'Windows':
    #dirlist = ( "c:/mma", "c:/program files/mma", "." )
    midiPlayer = ['']   # must be a list!
else:
    #dirlist = ( "/usr/local/share/mma", "/usr/share/mma", ".")
    midiPlayer = ["aplaymidi"] # Must be a list!

print 'sys.path[0] =', sys.path[0]
dirlist = [sys.path[0]]  # This the directory that contains the mma.py file.

This gets round the problem with fixed paths. The files in /usr/share/mma/*.py where being called instead of the ones I changed in ./mma/*.py

Happy new year.

Louis

* MMA-1.5c-dev1.zip (134.68 KB - downloaded 461 times.)
* mma.py.zip (1.45 KB - downloaded 502 times.)
Logged
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #7 on: January 01, 2010, 08:40:22 PM »

Good go! And I hope the New Year is a good one for you!

I'll do the merge this afternoon and give the code a run.

Comments will probably be later today ... or tomorrow. It's snowing like &*&$&$ here and I'll probably have to do some clearing later (my driveway is about 700m).

Just some quicky points:

  Naming: Plectrum is fine. But, STRUM would work (there wouldn't be a conflict with the option). I thought of GUITAR and STRINGS as well. Hmmm, the only other one I came up with was FRETTED. Really up to you ... and for users it won't matter much since it's all buried in style files.

 Options: Not a big deal to add. The setter should be in your file. Just that the variable storage is easier in pat.py since there isn't a "check other tracks for saving/restoring". There should have been one, I think, but it's not a big deal ... so we'll leave it alone and put added variables in pat.py.

 Let me look at the save when a new groove is loaded issue. The current groove name is stored in grooves.py.

Later ... need to dl your code before my web connect dies due to the snow (I'm on a wireless system ... my only choice other than satellite!).



Logged

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


WWW
« Reply #8 on: January 01, 2010, 09:30:46 PM »

Here's code for a notename -> midi value. I'd think it belongs in midiM.py. You might want to fiddle with the "middle" value.

Oh, and midiM.py will need to include the error code (from MMA.common import *) ... or return -1 on error. Probably better to just return -1 and let your code worry about it.

Code:
def error(s):
    import sys
    print s
    sys.exit(0)

def noteNameToMidiValue(s):
    """ Convert a name ('e', 'g#') to a MIDI value. """

    tb = { 'c': 0,  'c#': 1,  'd&': 1, 'd': 2, 'd#': 3,  'e&': 3,
           'e': 4,  'f&': 4,  'e#': 5, 'f': 5, 'f#': 6,  'g&': 6,
           'g': 7,  'g#': 8,  'a&': 8, 'a': 9, 'a#': 10, 'b&': 10,
           'b': 11, 'b&': 11, 'c&': 11,  'b#': 0 }

    # strip and count trailing '+' and '-'

    if '-' in s and '+' in s:
        error("Can't have both + and - in note name.")

    adjust = 0
    while s.endswith('-'):
        adjust -= 12
        s=s[:-1]
    while s.endswith('+'):
        adjust += 12
        s=s[:-1]

    try:
        value = tb[s] + 60  # puts into middle octave 60==5*12
    except:
        error ( "No such name: %s" % s)

    return value + adjust

for a in ('a', 'b', 'b#', 'g', 'g-', 'g++', 'q'):
    print noteNameToMidiValue(a)



Is this what you wanted?

There is another converter in patSolo.py, but I think it's easier to do it with a separate function.

Let me know.
Logged

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


WWW
« Reply #9 on: January 01, 2010, 10:25:34 PM »

To turn off vibrating strings, add the following to the start of doMidiClear() in pat.py (line 966):

[
Code:
   def doMidiClear(self):
        """ Reset MIDI settings. """

        if self.vtype == 'PLECTRUM':
            self.closeGroove(gbl.tickOffset)
      ....

This is called whenever a new groove is loaded and at the end of the file. I don't think it'll be needed anywhere else?Huh

The call crashes for me, but that is the patPlectrum code Smiley

A few things remain: mainly decisions on:

   - what items in your style to save/restore with a groove,
   - do you want to have different setting in each bar of a sequence?

I listened to a few samples generated with the new code and I think it sounds very, very good! This will definitely make MMA much better!
Logged

My online life: http://www.mellowood.ca
louisjb
Jr. Member
*
Posts: 16


« Reply #10 on: January 02, 2010, 12:36:06 AM »

change the offending line to

        for stringNo in range(len(self._vibrating)):

But now it fails with

Code:
 
File "/home/louis/active/src/mma-bin-1.5c-dev1/MMA/midi.py", line 533, in addNoteOnToTrack
    onEvent  = chr(0x90 | self.channel) + chr(note) + chr(v)
ValueError: chr() arg not in range(256)

because  self.channel = -1

Quote
I listened to a few samples generated with the new code and I think it sounds very, very good! This will definitely make MMA much better!
Yes I am very please my self. Basically it is very difficult to get realistic guitar sound on a midi tracks so I think MMA may get a lot more attention from people who want a realistic guitar sound on midi tracks.

Quote
It's snowing like &*&$&$ here and I'll probably have to do some clearing later (my driveway is about 700m).
I am very worried that you will get snowed in because you are too busy on the computor.

More post tomorrow because it getting late here now.
Logged
bvdp
Kara-Moon Master
****
Posts: 1436


WWW
« Reply #11 on: January 02, 2010, 12:48:52 AM »

To the code line at doMidiClear() add a channel test:

      if self.vtype == 'PLECTRUM' and self.channel != -1:

But, it still crashes Smiley But, later Smiley

Did the first snow-clearing this afternoon. Got a snowblower, so it's not too big a deal. Still, hard work and quite a lot of time away from the computer Smiley



Logged

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


WWW
« Reply #12 on: January 02, 2010, 01:14:29 AM »

Just a quick thought (over dinner I was thinking about this ... don't tell my wife!).

If you want to change instruments, you need to set a new tuning string with something like:

   Plectrum-Guitar Tuning e f g ...

Why not add to this with some predefined instruments. I'd suggest that things like:

      Plectrum-Guitar Tuning Banjo
      Plectrum-Guitar Tuning 12Guitar

etc. be permitted. Then in the setTuning code you'd just need something like:

      if len(..) == 1:
          if tuningstring.upper() == 'BANJO' ...
      etc.
      else:
          assume each string is specified.

Probably easier to all this with some tables. But, it's your code Smiley

I'd just like to be able to avoid having users balk at using alternate instrument configs.

Best ... getting late here as well.
« Last Edit: January 02, 2010, 01:19:39 AM by bvdp » Logged

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


WWW
« Reply #13 on: January 02, 2010, 05:12:49 PM »

Instead of changing the doMidiClear() in pat.py, we should make life simpler by overriding it. So, in patPlectrum.py add the new function:


    def doMidiClear(self):
        """ Reset MIDI settings, special hook for stopping strings. """
 
        self.closeGroove(gbl.tickOffset)
        PC.doMidiClear(self)


Still doesn't work. But, it's prettier Smiley
Logged

My online life: http://www.mellowood.ca
louisjb
Jr. Member
*
Posts: 16


« Reply #14 on: January 02, 2010, 07:19:31 PM »

Quote
Did the first snow-clearing this afternoon. Got a snowblower, so it's not too big a deal.

I forgot you know how to deal with snow over there. Over here you get half and inch of snow and it is on the front pages of all the papers and all the roads are gridlocked.

Attached is the latest version plectrum. In debug mode it now prints the chord shapes. I have renamed closeGroove to grooveFinish. I have shoved noteNameToMidiPitch at the end of the file but it probably belongs in util or somewhere.

The following three lines really need to be comment out but I left them in for debugging. It crashes when they are commented out because gbl.mtrks[self.channel].channel  is -1.

Code:
        print "grooveFinish offset=", offset, "self.channel=", self.channel, "gbl.mtrks[self.channel].channel=", gbl.mtrks[self.channel].channel
        if gbl.mtrks[self.channel].channel == -1:
            return

yes overiding is much better,

I really would like to get the grooveFinish code working as it sounds odd without it. I think you are passing the wrong offset to me eg 10752. It should should not be be bigger than 192*4 and offset should be reset to zero every bar.

Also I have got setTuning and capoFretNo working now. is it possible for you to connect them up to Tuning  and Capo in the plectrum definition in the mma file as I don't really know the best way to do this. Feel free to change patPlectrum.py

Louis

* patPlectrum2.py.zip (2.86 KB - downloaded 430 times.)
Logged
Pages: [1] 2
  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.066 seconds with 19 queries.