TriOS/lib/adm-wav.spin

364 lines
31 KiB
Plaintext

{{
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Digital To Analog Converter Engine │
│ │
│ Author: Kwabena W. Agyeman │
│ Updated: 1/11/2010 │
│ Designed For: P8X32A │
│ │
│ Copyright (c) 2010 Kwabena W. Agyeman │
│ See end of file for terms of use. │
│ │
│ Driver Info: │
│ │
│ The DACEngine runs a stereo digital to analog converter driver in the next free cog on the propeller chip when called. │
│ │
│ The driver, is only guaranteed and tested to work at an 80Mhz system clock or higher. The driver is designed for the P8X32A │
│ so port B will not be operational. │
│ │
│ Nyamekye, │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}
CON
''
'' 100Ω 1µF
DAC_Left_Pin = 08 '' ───┳─── Left Out
'' │
'' 10nF
'' │
'' 
''
'' 100Ω 1µF
DAC_Right_Pin = 09 '' ───┳─── Right Out
'' │
'' 10nF
'' │
'' 
VAR
word dataBlock[512]
word callerPointer
word callePointer
byte stopedOrStarted
byte signedOrUnsigned
byte bitsPerSample
byte numberOfChannels
word leftVolume
word rightVolume
long sampleRate
PUB getDataBlockAddress
return @dataBlock
PUB startPlayer '' 3 Stack Longs
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
'' │ Starts/Unpauses the stereo DAC player. The player will begin at whatever point it stopped at before. │
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
stopedOrStarted := true
PUB stopPlayer '' 3 Stack Longs
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
'' │ Stops/pauses the stereo DAC. The player will remember whatever point it stopped at. │
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
stopedOrStarted := false
PUB transferData '' 3 Stack Longs
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
'' │ Helps reliably transfers data to the stero DAC to play. Throttles data transfer speed to that of data play speed. │
'' │ │
'' │ Returns address of next data buffer to transfer data to. Does not return until data buffer is ready for transfer. │
'' │ │
'' │ At 8 bits per sample using 1 channel each data buffer is composed of 512 bytes with 512 samples per transfer. │
'' │ │
'' │ At 8 bits per sample using 2 channels each data buffer is composed of 512 bytes with 256 samples per transfer. │
'' │ │
'' │ At 16 bits per sample using 1 channel each data buffer is composed of 256 words with 256 samples per transfer. │
'' │ │
'' │ At 16 bits per sample using 2 channels each data buffer is composed of 256 words with 128 samples per transfer. │
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
repeat while(callerPointer == callePointer)
result := @dataBlock[256 & callerPointer]
not callerPointer
PUB clearData '' 3 Stack Longs
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
'' │ Clears all data in all player data buffers. │
'' │ │
'' │ Helps prevent old data from being played when changing to a new data transfer source. │
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
bytefill(@dataBlock, ((not(signedOrUnsigned)) & $80), 1024)
PUB changeLeftChannelVolume(newVolume) '' 4 Stack Longs
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
'' │ Changes the volume of the left channel. (0 to 100) │
'' │ │
'' │ NewVolume - New volume to output samples at. Samples are scaled by this value. Zero mutes the channel. │
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
leftVolume := (((newVolume <# 100) #> 0) * constant(65536 / 100))
PUB changeRightChannelVolume(newVolume) '' 4 Stack Longs
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
'' │ Changes the volume of the right channel. (0 to 100) │
'' │ │
'' │ NewVolume - New volume to output samples at. Samples are scaled by this value. Zero mutes the channel. │
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
rightVolume := (((newVolume <# 100) #> 0) * constant(65536 / 100))
PUB changeSampleSign(signed) '' 4 Stack Longs
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
'' │ Changes whether samples are signed or not. │
'' │ │
'' │ Signed - True to make all samples be interpreted as signed. False to make all samples be interpreted as unsigned. │
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
signedOrUnsigned := signed
PUB changeBitsPerSample(newWidth) '' 4 Stack Longs
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
'' │ Changes the bits per sample, 8 bits or 16 bits. │
'' │ │
'' │ NewWidth - New bits per sample to output samples at. Samples are sized by this value. (8 or 16) │
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
bitsPerSample := (newWidth == 16)
PUB changeNumberOfChannels(newNumber) '' 4 Stack Longs
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
'' │ Changes the number of channels, 1 channel or 2 channels. │
'' │ │
'' │ When set to 1 channel mode the driver will output samples to both channels at once. │
'' │ │
'' │ When set to 2 channel mode the driver will output samples to both channels at simultaneously. │
'' │ │
'' │ NewNumber - New number of channels to output samples at. Samples are grouped by this value. (1 or 2) │
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
numberOfChannels := (newNumber == 2)
PUB changeSampleRate(newRate) '' 4 Stack Longs
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
'' │ Changes the sample rate. The stereo DAC supportes samples rates from 1HZ to 88.2KHZ. │
'' │ │
'' │ NewRate - New sample rate to out samples at. Samples are outputted at the frequency specified by this value. │
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
sampleRate := (clkfreq / ((newRate <# 88200) #> 1))
PUB DACEngine(newRate) '' 4 Stack longs
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
'' │ Initializes the stereo digital to analog converter driver to run on a new cog. │
'' │ │
'' │ Default mode is 8 bits per sample with unsigned samples, 1 channel with muted volume, and playing stopped. │
'' │ │
'' │ Returns the new cog's ID on sucess or -1 on failure. │
'' │ │
'' │ NewRate - New sample rate to out samples at. Samples are outputted at the frequency specified by this value. │
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
changeSampleRate(newRate)
dataBlockAddress := @dataBlock
callePointerAddress := @callePointer
stopedOrStartedAddress := @stopedOrStarted
unsignedOrSignedAddress := @signedOrUnsigned
bitsPerSampleAddress := @bitsPerSample
numberOfChannelsAddress := @NumberOfChannels
leftVolumeAddress := @leftVolume
rightVolumeAddress := @rightVolume
return cognew(@initialization, @sampleRate)
DAT
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
' Stereo Digital To Analog Converter Driver
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
org
' //////////////////////Initialization/////////////////////////////////////////////////////////////////////////////////////////
initialization mov ctra, #((DAC_Left_Pin <# 31) #> 0) ' Setup counter I/O pins.
mov ctrb, #((DAC_Right_Pin <# 31) #> 0) '
movi ctra, #%0_00110_000 ' Setup counter modes to duty cycle mode.
movi ctrb, #%0_00110_000 '
mov dira, outputMask ' Setup I/O pin directions.
mov playerPointer, dataBlockAddress ' Setup data block pointer.
rdlong timeCounter, par ' Setup timing.
add timeCounter, cnt '
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
' Player
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
outerLoop rdbyte buffer, numberOfChannelsAddress wz ' Setup player mode.
muxz playerMode, #$1 '
rdbyte buffer, bitsPerSampleAddress wz '
muxz playerMode, #$2 '
test playerMode, #$1 wc ' Setup counter.
mov counter, #128 '
if_c_or_z add counter, #128 '
if_c_and_z add counter, #256 '
' //////////////////////Inner Loop/////////////////////////////////////////////////////////////////////////////////////////////
innerLoop rdlong buffer, par ' Wait until next sample output period.
waitcnt timeCounter, buffer '
rdbyte buffer, stopedOrStartedAddress ' If stopped loop continously.
tjz buffer, #innerLoop '
movs multiplicand, #leftVolumeAddress ' Get and output value.
call #decode '
mov frqa, sampleBuffer '
test playerMode, #1 wc ' Check number of channels.
if_c mov frqb, frqa '
if_c jmp #nextLoop '
movs multiplicand, #rightVolumeAddress ' Get and output value.
call #decode '
mov frqb, sampleBuffer '
nextLoop djnz counter, #innerLoop ' Loop.
' //////////////////////Outer Loop/////////////////////////////////////////////////////////////////////////////////////////////
rdword buffer, callePointerAddress wz ' Switch data block pointer.
if_z neg buffer, #1 '
if_nz mov buffer, #0 '
wrword buffer, callePointerAddress '
if_nz mov playerPointer, dataBlockAddress ' Setup data block pointer.
jmp #outerLoop ' Loop.
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
' Decode Value
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
decode test playerMode, #$2 wc ' Read data depending on size.
if_c rdbyte multiplyBuffer, playerPointer '
if_c add playerPointer, #1 '
if_nc rdword multiplyBuffer, playerPointer '
if_nc add playerPointer, #2 '
rdbyte buffer, unsignedOrSignedAddress wz ' Modify data depending on sign and size.
if_z_and_c sub multiplyBuffer, #$80 '
if_c shl multiplyBuffer, #24 '
if_c sar multiplyBuffer, #16 '
if_z_and_nc sub multiplyBuffer, wordAdjust '
if_nc shl multiplyBuffer, #16 '
if_nc sar multiplyBuffer, #16 '
multiplicand rdword multiplyCounter, 0 ' Setup inputs.
mov sampleBuffer, #0 '
abs multiplyBuffer, multiplyBuffer wc ' Backup sign.
rcr sampleBuffer, #1 wz, nr '
multiplyLoop shr multiplyCounter, #1 wc ' Preform multiplication.
if_c add sampleBuffer, multiplyBuffer '
shl multiplyBuffer, #1 wc '
tjnz multiplyCounter, #multiplyLoop '
negnz sampleBuffer, sampleBuffer ' Restore sign.
add sampleBuffer, longAdjust ' Center output value.
decode_ret ret ' Return.
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
' Data
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
wordAdjust long $8000 ' Edits word signed value.
longAdjust long $80000000 ' Edits long unsigend value.
' //////////////////////Pin Masks//////////////////////////////////////////////////////////////////////////////////////////////
outputMask long ((|<((DAC_Left_Pin <# 31) #> 0)) | (|<((DAC_Right_Pin <# 31) #> 0))) ' DAC Outputs.
' //////////////////////Addresses//////////////////////////////////////////////////////////////////////////////////////////////
dataBlockAddress long 0
callePointerAddress long 0
stopedOrStartedAddress long 0
unsignedOrSignedAddress long 0
bitsPerSampleAddress long 0
numberOfChannelsAddress long 0
leftVolumeAddress long 0
rightVolumeAddress long 0
' //////////////////////Run Time Variables/////////////////////////////////////////////////////////////////////////////////////
buffer res 1
counter res 1
playerPointer res 1
playerMode res 1
sampleBuffer res 1
timeCounter res 1
multiplyBuffer res 1
multiplyCounter res 1
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
fit 496
{{
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ TERMS OF USE: MIT License │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │
│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │
│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the │
│Software is furnished to do so, subject to the following conditions: │
│ │
│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the │
│Software. │
│ │
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │
│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │
│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}