Piano Sustenuto Effect

I wrote a script intending to achieve a cool result called the “Sustenuto Effect”. My intention is to create the effect of two people playing pianos. Here is how it should work:

  1. Play notes from MIDI Block M1 as normal until the sustain pedal is depressed.

  2. Then when notes are played and/or held on M1 and the sustain pedal is depressed: latch those notes and do not play any further notes from M1 until the sustain pedal is released. (This is not to be confused with AutoSustainer or Sustain because notes now played from M1 are ignored until you release the sustain pedal.)

  3. Now allow notes from M2 to be played but one octave higher. Until the sustain pedal is released.

  4. When the Sustain pedal is released:
    a. ignore notes played from M2
    b. release the M1 notes that were latched
    c. activate M1 to normal mode again

The object of the game is: The player would use the sustain pedal frequently to create the effect of another player joining in. The soundscape is very realistic and fun to play … and of course, it can be used with any Source. In my Rackspace, I am using the Stereo Piano from my PC2R, but you can use any source you like.

I will attach a Gig file that includes my script. The script almost works, but not entirely! It needs some help. I am using AllNotesOff to terminate the latch on M1 when the sustain pedal is released, but the AllNotesOff creates a timing issue. Try it and you will see for yourself. Maybe you can think of an alternative method to make the script run more smoothly. Any help would be appreciated.

Here is my script:

Var
M1 : MidiInBlock
M2 : MidiInBlock
FirstTime : Boolean
Sustain : Boolean
TempInt : Integer
CallBack : String
NoteArray : NoteMessage

Initialization
FirstTime = True
Sustain = False
End

On Activate
FirstTime = True
Sustain = False
End

On ControlChangeEvent(m : ControlChangeMessage) Matching 64 from M1

if GetCCValue(m) == 127 then
    Sustain := true
else
    Sustain := false
end


Select

    FirstTime == true And Sustain == false Do
       AllNotesOff(M1)

    FirstTime == true And Sustain == true Do

    FirstTime == false And Sustain == false Do
        AllNotesOff(M1)

    FirstTime == false And Sustain == true Do
        AllNotesOff(M1)

End

End

on NoteEvent(m : NoteMessage) from M1

if Sustain == false then
    SendNow(M1, m)
    FirstTime := true
else
    FirstTime := false
end

end

On NoteOffEvent(m : NoteMessage) from M1

if Sustain == false then
    SendNow(M1, m)
end

end

on NoteEvent(m : NoteMessage) from M2

if Sustain == true then
    SendNowRespectingParameters(M2, m)
 end

end

On NoteOffEvent(m : NoteMessage) from M2

SendNowRespectingParameters(M2, Transpose(m, 0))

end

OK, I give up: how do I attach my Gig File to my post?

Use the Upload button :slight_smile:
Upload

2 Likes

So it is not the equivallent of the sostenuto pedal of a grand piano.

Did you consider using StopAllPendingNotes which necessitates to use NoteTrackers.

Yes, it is exactly equivalent to the sostenuto pedal of a grand piano. :slight_smile:

I didn’t know this function existed. I will have to give it a try. Ok, where can I find examples of Note Tracker and StopAllPendingNotes. Unless I am missing something, the Script documentation lacks examples. Do you have examples of all the functions and types etc.?

Thanks for writing this. If I may, I’d like to propose some changes that would be considered best practices for GPScript (and indeed some other languages) and will actually make the script a little more efficient.

For example, instead of

if GetCCValue(m) == 127 then
    Sustain := true
else
    Sustain := false
end

try just

 Sustain = GetCCValue(m) == 127 

Instead of

FirstTime == true And Sustain == false Do

try just

FirstTime And Not Sustain Do

Instead of

if Sustain == true then

just write

if Sustain then 

There are other improvements but the above are useful idioms with which to be aware.

1 Like

Thanks. Can we get many more short examples of using various functions and types plz?

Have a look into the GPScript list of functions

Var
 nt : NoteTracker

nt.GotNote(anyNoteMessage) // keeps the NoteMessage in the NT if it is a Note On or remove it if it is a NoteOff

nt.StopAllPendingNotes() // Sends a Note Off for each note in the NT

I don’t see this screen for upload when I am in the Editor. What am I doing wrong? :slight_smile:

Dosen’t simple drag n’ drop works for you?

1 Like

I tried coding StopAllpendingNotes() but I am getting a compile error (Argument type mismatch). The syntax requires MidiInBlock and NoteTracker. Since I am doing this function within the ControlChangeEvent, there is no value for the MidiInBlock.

Here is my code snipit:

On ControlChangeEvent(m : ControlChangeMessage) Matching 64 from M1

Sustain := GetCCValue(m) == 127 

Select
    FirstTime And Not Sustain Do
       //AllNotesOff(M1)
       nt.StopAllPendingNotes(M1,nt)

    Not FirstTime And Not Sustain Do
       nt.StopAllPendingNotes(M1,nt)

    Not FirstTime And Sustain Do
       nt.StopAllPendingNotes(M1,nt)
End

End

Here is my GigFile:

Sustento.gig (9.7 KB)

Please include the compile error in your report

It is:
StopAllPendingNotes(M1,nt)

or

M1.StopAllPendingNotes(nt)

I cannot further check your gig file for the moment, as I just have an iPhone in my hands…

1 Like

I can confirm, tested with M1.StopAllPendingNotes(nt) :wink:

1 Like

Thank you so much! :slight_smile: My script works perfectly now. I will attach the gig file so members can use it. This is a very useful script and should be shared, so enjoy my friends.

All you have to do is change the sources to your liking. EG; in my first Rackspace, I used only one source, but in Rackspace 2 I used two different sources for another effect.

Sustento.gig (30.1 KB)

4 Likes