Difference between revisions of "A/V Control Commands"

From pinHeck Wiki
Jump to: navigation, search
 
(13 intermediate revisions by the same user not shown)
Line 1: Line 1:
 +
The PIC32 runs main game code, the Parallax Propeller (Prop) handles audio/video. They do not share RAM, thus the Prop only knows what you tell it via '''A/V Control Commands'''.
 +
 
These are the commands you call from the main game kernel to control the Propeller A/V. Most commands do not return a value unless noted.
 
These are the commands you call from the main game kernel to control the Propeller A/V. Most commands do not return a value unless noted.
 +
 +
== Audio ==
 +
 +
pinHeck system can play (4) channels of 22,050Hz stereo WAV files at the same time. The fourth channel (channel 3 logical numbers) is always used for music.
 +
  
 
[[playSFX(which channel, which folder, clip0, clip1, priority)]]
 
[[playSFX(which channel, which folder, clip0, clip1, priority)]]
  
 +
[[playSFXQ(which channel, which folder, clip0, clip1, priority)]]
 +
 +
[[stereoSFX(which channel, which folder, clip0, clip1, priority, left volume, right volume)]]
  
== playSFX(which channel, which folder, clip0, clip1, priority) ==
+
[[playMusic(clip0, clip1)]]
  
 +
[[playMusicOnce(clip0, clip1)]]
  
'''Example:'''
+
[[stopMusic()]]
  
playSFX(0, 'B', 'A', 'A', 255);
+
[[volumeSFX(which channel, volume left, volume right)]]
  
Plays audio file "BAA.wav" from the SFX/_FB folder on Channel 0 at top Priority.
+
[[fadeMusic(fade speed, fade target)]]
  
 +
[[repeatMusic(what state)]]
  
Use channels 0-2. Channel 3 is reversed for music (usually always playing)
+
[[musicLoop(whichChannel, startingPoint, loopingPoint, jumpPoint)]]
  
If a sound file is currently playing on Channel 0 at a higher priority than an incoming sound, then the new sound will not play. What I tend to do is use channel 0 for voice prompts, channel 1 for mid-table sound effects (targets, slings etc) and channel 2 for back of the table sounds (pop bumpers and rollovers) This helps "space out" the sounds during a multiball.
+
== Video ==
  
As an example, run your normal pop bumper sound on channel 2 with a priority of 250. Then, if you have a "Super Pops" sound or callout, use the same channel but with a priority of 255. Reason for this is let's say you get 50 pops and it says "SUPER POPS!" Now you'll probably get additional pop hits while this voice plays. By calling the voice at 255, and the pops at 250, it ensures the normal pop sound won't override the voice prompt until the priority 255 voice prompt finishes.
+
pinHeck can play 1 video layer at 30 FPS, or combine 2 layers (with black as transparency) at 15 FPS. Both layers have forward/backward control, can advance 1-3 frames at a time, or you can manually jump to frames for a video mode.
  
It might be tempting to avoid this by using different channels all the time, but the problem there is you may have voices overlapping which sounds bad.
+
Note that pinHeck audio/video is NOT interleaved (contained in same file) This is because quite often you'll have the same video with several different random audio calls attached to it.
  
The 3 characters must be valid ASCII filename characters, and the first character MUST be A-Y (to match the folders). The sound data is subdivided into folders to greatly reduce search time (worst case is 5ms, usually less)
 
  
You CAN however mix and match variables to create randomized or progress-based callouts. For example:
+
[[video(which folder, clip0, clip1, attributes, progressBar, priority)]]
  
playSFX(0, 'M', 'D', '0' + random(4), 255);
+
[[videoQ(which folder, clip0, clip1, attributes, progressBar, priority)]]
  
Will randomly pick from:
+
[[killQ()]]
  
MD0.wav
+
[[stopVideo(what state)]]
  
MD1.wav
+
[[videoPriority(new priority)]]
  
MD2.wav
+
[[videoControl(whichLayer, controlByte, xPos, yPos, frameTarget)]]
  
MD3.wav
+
[[layerLoad(whichLayer, v1, v2, v3, vidAttributes, controlByte, xPos, yPos, vP, DMDsearch)]]
  
What is does is takes the ASCII value of '0' (48) and adds a random number between 0 and 3 to it. Or you could also do this:
+
[[customScore(v1, v2, v3, vidAttributes)]]
  
playSFXQ(0, 'M', 'D', '@' + progress, 255);
+
[[killCustomScore()]]
  
Progress variable would increase every time you make a shot, so the clips could be labeled:
+
== Graphics ==
  
MDA.wav
+
Graphics are anything on the display that isn't part of the video. This includes numbers, progress bars, Ball and Credit indicators, and sprites (character set graphics you can move around)
  
MDB.wav
 
  
MDC.wav
+
[[numbers(which number, number Type, number X, number Y, number value)]]
  
MDD.wav
+
[[numbersPriority(whichNumber, numType, numX, numY, numValue, matchPriority)]]
  
Notice how we start with '@' (64) and then add Progress? That's because making the shot increments Progress by 1, so it will never be 0. 64+1=65 which is the letter A.
+
[[killNumbers()]]
  
AMH took this a bit further with code like:
+
[[killScoreNumbers()]]
  
playSFX(0, 'L', 48 + hotProgress[player], random(4) + 65, 255);
+
[[killTimer(which number)]]
  
So for each shot that advances the Hotel, there are 4 random phrases per shot.
+
[[characterSprite(which number, sprite attribute, sprite X, sprite Y, sprite height, sprite value)]]
  
L1A.wav      -Four different voices for Shot 1
+
[[showValue(number value, flash time, score flag)]]
  
L1B.wav
+
[[showProgressBar(which Graphic, bar brightness, x pos, y pos, length of bar, height of bar)]]
  
L1C.wav
+
[[value(xpos, ypos, the value)]]
  
L1D.wav
+
[[text(xpos, ypos, the text string)]]
  
L2A.wav      -Four different voices for Shot 2, and so on
+
[[graphicsMode(do what, the modifier)]]
  
L2B.wav
+
[[loadSprite(clip0, clip1, clip2, doLoad)]]
  
L2C.wav
+
[[sendSwitches()]]
  
L2D.wav
+
== Scorekeeping ==
  
 +
Again, the Propeller A/V processor has no clue what any scores are unless you tell it. Current player's score is always being changed, and all player scores / ball and credit numbers are updated at every drain cycle.
  
Techniques like these can greatly randomize your audio and keep it fresh every time!
 
  
 +
[[Update(attract mode state)]]
  
 +
[[addScore(score amount)]]
  
== playSFXQ(which channel, which folder, clip0, clip1, priority) ==
+
[[setScore(which player)]]
  
 +
[[manualScore(whichScore, whatValue)]]
  
'''Example:'''
+
[[EOBnumbers(whichNumber, number value)]]
  
playSFXQ(0, 'B', 'A', 'A', 255);
+
[[sendHighScores(which score)]]
  
 +
[[sendInitials(which player, which character)]]
  
Works just like playSFX but queues the clip to play once whatever is already playing in that channel finishes.
+
== EEPROM Access ==
  
Let's use Attack from Mars as an example. Destroying the second saucer has the explosion + "Well Done" and then says "Extra Ball is lit". If you needed to do something like this in your game, you'd play the normal sound via playSFX, then queue up whatever is said next with the playSFXQ command. This allows you to separate things out.
+
The PIC32 uses the top half of the removable Propeller EEPROM for data storage. It has many more rewrite cycles than the flash memory contained inside the PIC32.
  
In America's Most Haunted, revealing a Ghost Minion triggers a randomized quote. playSFX is used so the character says "It's a class five..." and playSFXQ is used to finish the quote "...Free Roaming Vapor Mist Anomaly!"
+
Because of this, EEPROM access is kind of slow (up to 20ms for a long write as it also verifies the write) It is best to only do it during drain cycles or between games.
  
In the code it looks like this:
 
  
playSFX(0, 'M', 'C', '9', 255); //You can keep beating them, but they only go up to Class 9
+
[[writeEEPROM(which address, what value)]]
video('M', 'F', '9', allowSmall, 0, 250); //Ghost level cap at 9
+
playSFXQ(0, 'M', 'D', '0' + random(10), 255); //Something Something Specter!
+
  
It's a good idea to do something between the SFX calls to ensure the first sound gets going before you enqueue a second.
+
[[readEEPROM(which address)]]

Latest revision as of 15:24, 12 September 2015

The PIC32 runs main game code, the Parallax Propeller (Prop) handles audio/video. They do not share RAM, thus the Prop only knows what you tell it via A/V Control Commands.

These are the commands you call from the main game kernel to control the Propeller A/V. Most commands do not return a value unless noted.

Audio

pinHeck system can play (4) channels of 22,050Hz stereo WAV files at the same time. The fourth channel (channel 3 logical numbers) is always used for music.


playSFX(which channel, which folder, clip0, clip1, priority)

playSFXQ(which channel, which folder, clip0, clip1, priority)

stereoSFX(which channel, which folder, clip0, clip1, priority, left volume, right volume)

playMusic(clip0, clip1)

playMusicOnce(clip0, clip1)

stopMusic()

volumeSFX(which channel, volume left, volume right)

fadeMusic(fade speed, fade target)

repeatMusic(what state)

musicLoop(whichChannel, startingPoint, loopingPoint, jumpPoint)

Video

pinHeck can play 1 video layer at 30 FPS, or combine 2 layers (with black as transparency) at 15 FPS. Both layers have forward/backward control, can advance 1-3 frames at a time, or you can manually jump to frames for a video mode.

Note that pinHeck audio/video is NOT interleaved (contained in same file) This is because quite often you'll have the same video with several different random audio calls attached to it.


video(which folder, clip0, clip1, attributes, progressBar, priority)

videoQ(which folder, clip0, clip1, attributes, progressBar, priority)

killQ()

stopVideo(what state)

videoPriority(new priority)

videoControl(whichLayer, controlByte, xPos, yPos, frameTarget)

layerLoad(whichLayer, v1, v2, v3, vidAttributes, controlByte, xPos, yPos, vP, DMDsearch)

customScore(v1, v2, v3, vidAttributes)

killCustomScore()

Graphics

Graphics are anything on the display that isn't part of the video. This includes numbers, progress bars, Ball and Credit indicators, and sprites (character set graphics you can move around)


numbers(which number, number Type, number X, number Y, number value)

numbersPriority(whichNumber, numType, numX, numY, numValue, matchPriority)

killNumbers()

killScoreNumbers()

killTimer(which number)

characterSprite(which number, sprite attribute, sprite X, sprite Y, sprite height, sprite value)

showValue(number value, flash time, score flag)

showProgressBar(which Graphic, bar brightness, x pos, y pos, length of bar, height of bar)

value(xpos, ypos, the value)

text(xpos, ypos, the text string)

graphicsMode(do what, the modifier)

loadSprite(clip0, clip1, clip2, doLoad)

sendSwitches()

Scorekeeping

Again, the Propeller A/V processor has no clue what any scores are unless you tell it. Current player's score is always being changed, and all player scores / ball and credit numbers are updated at every drain cycle.


Update(attract mode state)

addScore(score amount)

setScore(which player)

manualScore(whichScore, whatValue)

EOBnumbers(whichNumber, number value)

sendHighScores(which score)

sendInitials(which player, which character)

EEPROM Access

The PIC32 uses the top half of the removable Propeller EEPROM for data storage. It has many more rewrite cycles than the flash memory contained inside the PIC32.

Because of this, EEPROM access is kind of slow (up to 20ms for a long write as it also verifies the write) It is best to only do it during drain cycles or between games.


writeEEPROM(which address, what value)

readEEPROM(which address)