Reference: http://help.adobe.com/en_US/Director/11.5/UsingScripting/WSAC788789-A3A0-4993-BE09-C4E33D958427.html
Audio data from a sound object or a mixer can be accessed, processed and passed back to the audio engine and the audio engine will play the processed audio chunk. The sample program below just reads the PCM data from the sound object and find the peak value in each chunk and displays it to the user.
The steps to get the peak value from the sound object is as follows
- Register a callback function with the sound object
- Save the PCM data chunk obtained in each callback
- Find the peak value in the last saved chunk in every exitFrame.
global gByteArray --
Byte Array to save PCM data using which the peak is calculated
global gMix --
Global Mixer
global gSO --
Sound Object of which peak is calculated
global gValidLength --
Length of valid data in the gByteArray
The below code creates a new byteArray, mixer and sound object. Registers a callback function with the sound object so that we get the PCM data of the sound object’s audio chunk. Note that the callback is registered as #readOnly. i.e. If the audio chunk that is passed in the callback function is modified that will have no impact in the audio playback. For the change in audio chunk to be reflected the callback has to be registered as #readWrite.
Also note that the bufferSize of the mixer is set to 50 ms. This mean that the callback will be called almost every 50 ms and also it will have 50 ms data. In some cases this might vary upto 2 buffersizes!
on startmovie
-- Create a new
ByteArray
gByteArray = bytearray()
gValidLength = 0
-- Display the
peak value
member(1).text = string(0)
-- Create a new
Mixer
gMix = new(#mixer)
-- Add a sound
object to it
-- Let it loop
infinitely
gSO = gMix.createSoundObject("soundObj1", member(3), [#loopCount:0] )
-- Register for
byteArray output.
gSO.registerByteArrayCallback( #preFilter, #getPeak, #readonly )
-- Set the
mixer's format to that of the sound object so that there is no reformatting
required
gMix.channelCount = gSO.channelCount
gMix.bitDepth = gSO.bitDepth
gMix.sampleRate = gSO.sampleRate
-- Set the
Mixer's bufferSize to 50.
-- We get
callback called almost at 50 ms intervals
gMix.bufferSize = 50
-- Finally, play
the mixer!
gMix.play()
end
on stopMovie
-- Unregister the
byteArray callback
gSO.unregisterByteArrayCallback()
-- Erase the
Mixer
if not voidp(gMix) then
gMix.erase()
end if
-- Display the peak
value
member(1).text = string(0)
end
on getPeak pByteArray, bitDepth, sampRate, numChannel
-- Copy the most
recent PCM data into global byteArray
gByteArray = pByteArray
-- Update the
length of the byteArray
gValidLength = pByteArray.length
end
8 bit PCM values have values between 0 and 255. The below code calculates the peak value for the PCM data available in gByteArray.
This code works only for 8 bit, mono files!
For 16 bit-depth audio the PCM values can range from -32768 to +32767 and also the code should take care of endianess.
on exitFrame
-- If there's not
any data to process just return
if gValidLength = 0 then
return
end if
-- Set the
initial peak value to 0
maxValue = 0
-- Iterate
through each of the byte and get the peak value
repeat with i = 1 to gValidLength
if maxValue < gByteArray[i] then
maxValue = gByteArray[i]
end if
end repeat
-- Reset the
valid data length
gValidLength = 0
-- Display the
peak value
member(1).text = string(maxValue)
end
The calculation of the peak value is done in exitFrame and not in the callback function for performance reasons.
In case the audio data need to be updated and it should get reflected in the audio playback (#readWrite) then the callback should save the most recent chunk into a global byteArray and pass the processed byteArray back. The saved byteArray is processed in the next exitFrame. This will ensure good performance at the cost of a bufferSize duration of delay.
For volume factor to be reflected in the peak Value we have to multiply the peak value with the scaled volume level.
Download the sample movie here
Feedback:
If you have any questions or comments concerning this
article, please send a message to shrinidhi@gmail.com |