“Hear me now and believe me later”
—Hans
In the first part of this series we merely looked at the script, in the second part we did in fact get in and make changes to the script but since we were linting, if we did it right the changes made no difference to how the table played.
In this post we are going to do some significant script refactoring. Get your surgical gloves on.
Read the descriptions for many of the VPX tables posted online and you will at some point come across a reference to Fleep sounds. What is that?
My best guess is that “Fleep” is a username. But more to the point, the pinball tables that indicate they have Fleep sounds are talking about a collection of audio files that are generally regarded as very high quality as well as code in the table’s script that takes advantage of the positional audio feature of VPX (pan sounds: left and right; fade sounds: front and back). In short the pinball tables have more dynamic audio, better pinball sounds.
As an example of the Fleep sounds themselves: you know the “drain” is where your ball goes when it slips between your flippers — Fleep sounds have twelve different sounds for the ball going into the drain. They’re all similar of course but that random and subtle variation adds to the realism of the table.
I started my journey modifying VPX tables initially by grabbing both the sounds and sound code from a “Fleeped” table and shoving them into a table that didn’t sound as good, but in time I began to modify and refactor the code as well as augment the sound collection with additional sounds that are specific to EM pinball tables. I ended up calling the package just EM Sounds.
I’m going to walk you through how to grab the sound code that I came up with as well as the library of sounds I am currently using and “EM Sound” Teacher’s Pet.
In this post, we’re going to move fast and break things!
(And then move a little more slowly … and fix the things we broke.)
Quick, just get in the car and do the following, I’ll explain later.
With the linted version of Teacher’s Pet, select the code beginning at Positional Sound Playback Functions
banner and begin your selection to include it).
And select up to OnBallBallCollision
subroutine).
Hit the
That was easy. What we did was to remove a lot of code that we have a replacement for or will no longer need. But we have also broken the script. Let’s add our own positional sound code in the old one’s place.
The sound code I’m going to use is kept up to date on Github. Github is a site that contains mostly source code to computer programs. In fact it is where the sources to Visual Pinball live. If you click on this link you will be taken straight to the sound code file.
Copy the text to the pasteboard by clicking the widget I indicate above. Go back to VS Code (Visual Studio Code)
or wherever you are editing Teacher’s Pet and
If you scroll up to the end of HideOptions()
you’ll see that our new code begins with a
comment banner with EM Sounds
.
Okay, we have our new sound code but the script to Teacher’s Pet is still broken. Now begins the task of fixing things. If you enjoyed linting in the previous post, you’ll love this.
First things first. EM Sounds has an initialization routine that we want to call before any sounds
are played. It is called EMSInit()
and it looks like this:
I promised myself I would not dive into the code in this post but the above is so simple it serves as a gentle introduction to how this all works.
EMSInit()
just has two lines of code. It expects you to pass it a parameter it will refer to as
TableObj
. It is only interested in the width and height properties of TableObj
(TableObj.Width
and TableObj.Height
) — it assigns them to globals
TableWidth
and TableHeight
.
Looking a few lines before, you can see that
TableWidth
and TableHeight
have default values (1000 and 2000 respectively) but we want
the real dimensions of the pinball table — and that is the purpose of this routine.
As we’ll see later, EM Sounds will use the width to decide how to pan a sound left and right, the height to decide how to fade a sound from front to back.
We want to call EMSInit()
from somewhere in Teacher’s Pet.
If you recall back to the very first part in this series, we looked at the first subroutine in the script called
Table1_Init()
. Let’s scroll back up there again, near the top of the script file.
I’ve wrestled with how best to convey in this post all the small changes made in Teacher’s Pet to call the new sound code. The best way I could come up with was to do a file compare in VS Code between the previously linted version of Teacher’s Pet and the one I have modified for EM Sound support.
There is a green highlight in the “diff” (difference) below with a small plus sign (+) to the left. This indicates that this line of code was added.
This indicates that I inserted just one line before the call to LoadEM
.
That’s all that is needed to initialize the EM Sound code. EMSInit
is
the initialization routine, and we pass the routine the object representing the pinball table,
Table1
.
That was easy enough but what follows is a little more tedious. There are numerous places in Teacher’s Pet
where the script calls a VPX function called PlaySound
. For almost every instance we have a
preferred routine in EM Sounds that we want to call instead. Each replacement EM Sounds routine is specifically
tailored to a specific kind of sound. For example, we have a routine for when the player presses the left
flipper button, another sound routine to call when the player releases the left flipper button. Etc.
Starting at the top of the script, use the code editor to search for
The very first instance (shown above) is commented-out code. Cool, we can ignore it. But did you notice in the
search field that there are 144 instances of PlaySound
? Yeah, get comfortable. Make some tea. Take breaks.
Continue searching and we get to four PlaySound
calls in the routine Table1_KeyDown
.
Another diff follows. A red highlight indicates lines of code in Teacher’s Pet that were changed
or removed, the green highlight indicates lines of code that were changed or added.
I’ll explain later, but the PlaySound
calls that referred to a “buzz” sound were
stripped out. The other PlaySound
calls though I left but I commented them out. (I know, it’s
subtle, but the diff shows green text indicating a “comment” — you can just see the small
apostrophe at the start of each line of commented-out code). I chose to leave those calls as placeholders —
temporarily.
The new code added are calls to EMSPlayLeftFlipperActivateSound
and
EMSPlayRightFlipperActivateSound
. I pass an object to each of those calls: LeftFlipper
and RightFlipper
(respectively).
On to the next PlaySound
…
The above shows the simplest kind of substitution. Wherever the script used to want to play a coin sound, we have a
specific call: EMSPlayCoinSound
.
Notice that almost all the EM Sounds calls have had a form of EMSPlayXSound
(where “X” might
be “Coin” or “FlipperActivate”).
Continuing…
Above, replace with EMSPlayStartupSound
.
The next instances of PlaySound
are in the Table1_KeyUp
function. First, the sound for
releasing the plunger:
And then the counterpart to the flipper activated calls, we have EM Sounds calls for when the player releases the flipper buttons, or deactivates the flippers:
As before with the flipper calls, I left a couple lines of code as placeholders — commenting them out. We’ll revisit them later, but in case you’re already curious, it’s because those lines of code have references to something called “DOF”.
But lets get back to replacing PlaySound
calls.
Above, if the ball goes down the drain (“hits” the drain object) pass the object Drain
to
EMSPlayDrainSound
.
Right slingshot:
Left slingshot:
Again, for the slingshots I leave the original code in place but commented-out (because of “DOF” stuff).
There are three very similar bumper routines in Teacher’s Pet but I am showing you only the one above
for Bumper1_Hit
.
Since all three refer to DOF in their PlaySound
calls, I am leaving the code in place but commented
out. The only thing then that is really different between the three bumper routines is that the object passed to
EMSPlayMiddleBumperSound
is obviously Bumper2
in Bumper2_Hit
and
Bumper3
in Bumper3_Hit
.
There are three different bumper routines in EM Sound — top, middle and bottom variants. They use different
sound resources and so sound slightly different. You'll have to make a judgement call as to where you think the
bumpers on the table you are editing are. I decided the Teacher’s Pet bumpers were more or less in the
middle and so called EMSPlayMiddleBumperSound
.
Moving on…
There are a bunch of trigger routines that look like the above. A simple substitution. Again for brevity I am only showing you one such example above.
The next run of PlaySound
routines are for the kickers, of which there are quite a few in
Teacher’s Pet. I did something a little different in the case of the kickers though. Below is
for the first kicker — the rest of the kickers are similar.
Again leaving the original calls as placeholders, commenting out.
The original script called PlaySound
with a sound called “scoopexit”. EM Sounds
has a substitute routine for kickers called EMSPlaySaucerKickSound
, but when I substituted
this routine for a “scoopexit” in another VPX table, I had a player comment that the substitute
sound did not ring true to the actual pinball table. So I thought for Teacher’s Pet I would
stick with the “scoopexit” sound.
As you can see though, there is an EM Sounds routine I used called EMSPlaySoundAtVolumeForObject
.
I know it’s a long routine name, but maybe self-explanatory. You pass it the name of the sound
(“scoopexit”) as well as the volume at which you want to play the sound and an object so it
can “position” the sound. For the volume I created a constant.
Since there are a number of places following in the script for kicker sounds, having the one constant allows us to change the value of the volume in one place and it affects all three bumpers if we want to adjust it in the future.
Moving on. Below a simple substitution call for the knocker and click sounds.
“DOF” is in the knocker PlaySound
call so again we leave it commented out anticipating a
future change.
Next up: another simple substitution.
We’re almost done with the PlaySound
stuff by the way.
EM Sounds has two flavors of sounds it plays for EMSPlayStartBallSound
so we specify which
one with an integer — zero (0) in the following case.
Substitute for "MotorLeer" (whatever that is) follows:
The other flavor of EMSPlayStartBallSound
follows:
The diff for the subroutine PlayChime()
was kind of a mess so I am not showing it to you.
Instead, here is the finished code I substituted for the original code.
You’ll have to look at the old subroutine in Teacher’s Pet for yourself. It was quite a bit more complicated — an example of a Loserman76 boilerplate subroutine that could be used in a pinball table having three chimes or a table having two bells. When I researched Teacher’s Pet (on YouTube) I saw that it was a table with only two bells. So the replacement subroutine above is tailored to work only for the two-bell pinball table case.
Hey, that’s all the changes we need to make for PlaySound
. The EM Sounds code follows and it
makes calls to PlaySound
but that is expected.
In the first post in this series we saw a comment banner for Object sounds
in the script. There
are some PlaySound
calls there that I am going to leave for now. I will tell you that VPX will
definitely halt when we play the table and one of those Object sounds
routines are called. It
will be instructive though to let VPX “crash” and then deal with them when it happens.
Near the bottom of the file there are a few more calls to
PlaySound
but they are not related to game-play. They’re just sounds that are triggered
as you are entering your initials for a high score. There’s no advantage to change these over to
use EM Sounds.
One more change we need to make so that VPX is happy though is shown below in a diff:
A global called tnob
that we deleted earlier was replaced with one called NumberOfBalls
in EM Sounds. That same variable is used in the shadow code, so we simply need to substitute the new variable name.
(tnob
was one of those obtuse variable names that bothered me — it took me way too long to
realize that it stood for “the number of balls” so I renamed it.)
While we just finished putting the script back together in a way that will make VPX happy, we’re not out of the
woods yet. For the next steps however we’ll move back to the VPX environment. If you used a separate code editor like
I did, it is time to
To keep you (and me) from having to scroll so much in one blog post, I’m going to wrap this one up here. But continue to the next post, because we still need to add the new sound resources and fix a few more lines of the script to be able to enjoy our new sound code.