P2 Audio Out

in Propeller 2
Has anybody sent audio out the stereo outputs of the P2 AV board? I'm interested in seeing some PASM code that does that.
Comments
I also wonder if a P2 could software decode MP3? I heard the Cortex M4 can do it.
Although I don't see a lot of MP3s around these days, the world has moved on (mostly to OPUS, as far as I can tell. And of course lossless formats).
Also...
OPLcog, anyone?
At work we broadcast a live 1 hour video every week, plus an additional one each month. We also produce audio versions of these programs in MP3 format and make video and audio podcasts of these too. We also do a short ~5 minute video and audio each week, again available in MP3.
So I don't think MP3 will be replaced any time soon.
It would be interesting to throw these audio codecs at the existing C compilers for P2. We all like efficient code, but if a C version is fast enough... Based on the benchmarks I've seen, my first choice would be riscv-p2.
Storage is much cheaper now than when MP3 became popular. It's possible that MP3 would have advantages of computational complexity or code size compared to newer codecs. And I think it's old enough now to be patent free.
That one is lean, mean, accurate
Could decode 256mbps on 30Mhz MIPS R4k
Many existing players were derived from that software base. It's really pretty great.
Years ago, I compiled it on irix 5.3. The sound quality was very impressive, and it would do that 256 megabits over an NFS share, meaning the network stack was also active, along with the indigo magic Desktop.
Pity, I never did profile it memory use wise.
OPL?? That was a programming (Our Programming Language) language at a company I worked for eons ago. Pretty sure that is not what you are referring to so please enlighten me. Way too many search results to pick from.
Here is the P2 specific audio code from SIDcog.
First I setup some constants...
L_PIN = 0 R_PIN = 1 SYSTEM_CLOCK = 250000000 SAMPLE_RATE = 250000 'DAC_MODE = %00001_0 ' DAC 8-bit noise 'DAC_MODE = %00010_0 ' DAC 16-bit dither, noise DAC_MODE = %00011_0 ' DAC 16-bit dither, PWM DIR_MODE = %01 ' Output enabled, overrides DIR INIT_8BIT_DAC_VALUE = 128 'ANALOG_OUT_MODE = %10100 ' 990 ohm, 3.3V DAC mode 'ANALOG_OUT_MODE = %10101 ' 600 ohm, 2.0V DAC mode 'ANALOG_OUT_MODE = %10110 ' 123 ohm, 3.3V DAC mode ANALOG_OUT_MODE = %10111 ' 75 ohm, 2.0V DAC mode SMARTPIN_DAC_MODE = (ANALOG_OUT_MODE << 16) | (INIT_8BIT_DAC_VALUE << 8) | (DIR_MODE << 6) | DAC_MODE SAMPLE_PERIOD = SYSTEM_CLOCK / SAMPLE_RATE 'CPU cycles between sample updates
Here is the PASM init routine...
wrpin smartConfigAudioDAC, #L_PIN ' Config smartpin DAC mode on "left" pin wrpin smartConfigAudioDAC, #R_PIN ' Config smartpin DAC mode on "right" pin wxpin samplePeriod, #L_PIN ' Set sample period for left audio channel wxpin samplePeriod, #R_PIN ' Set sample period for right audio channel dirh #L_PIN ' Enable smartpin DAC mode on left pin dirh #R_PIN ' Enable smartpin DAC mode on right pin setse1 #%001_000000 | L_PIN ' Event triggered every new sample period (when "left in pin rises")
Note the "setse1" instruction, it is used to trigger an event everytime the "left" smartpin NCO wraps and the "left in pin rises". (@SAMPLE_RATE)
the "001" is the event mode that selects that the event should trigger on a pin rising. (everytime the NCO wraps it sets the IN state high)
Then for every new sample processed you have to send it to the pin(s) and wait the exact number of remaining CPU cycles before starting the processing of the next sample...
wypin r1, #L_PIN ' Output sample on left channel wypin r1, #R_PIN ' Output sample on right channel waitse1
The "waitse1" waits for the selectable event 1 that occours @SAMPLE_RATE and acknowledges it.
One more thing... The sample gets updated exactly when the NCO wraps and NOT when "wypin-ning".
I think I can go as low as 190 MHz?? Even when all bells and whistles are activated. It's 8 times the sample rate of SIDcog on the P1. The performance boost comes from 3 different things. 2x from faster instruction execution, 2x from faster clock rate and 2x from P2 specific optimizations such as HW multiplication, "bit twiddling" instruction, block moves. etc.
It may even be possible to hit 500 kHz sample rate with moderate overclocking and more P2 specific optimizations.
I compile with p2asm and have questions.
first smartConfigAudioDAC is not defined
wrpin smartConfigAudioDAC, #L_PIN
Second Can I replace samplePeriod
wxpin samplePeriod, #L_PIN
with this SAMPLE_PERIODSAMPLE_PERIOD = SYSTEM_CLOCK / SAMPLE_RATE
Is that planned with the smartpins so that I touch the pin directly to the probe(e.g. #L_PIN) and need nothing else?
It must not be event or interrupt triggered.
Thank you for help.
smartConfigAudioDAC = SMARTPIN_DAC_MODE
samplePeriod = SAMPLE_PERIOD
You must register the event even if you dont want to do any interrupt handling!
const L_PIN = 0 R_PIN = 1 SYSTEM_CLOCK = 250000000 SAMPLE_RATE = 250000 'DAC_MODE = %00001_0 ' DAC 8-bit noise 'DAC_MODE = %00010_0 ' DAC 16-bit dither, noise DAC_MODE = %00011_0 ' DAC 16-bit dither, PWM DIR_MODE = %01 ' Output enabled, overrides DIR INIT_8BIT_DAC_VALUE = 128 'ANALOG_OUT_MODE = %10100 ' 990 ohm, 3.3V DAC mode 'ANALOG_OUT_MODE = %10101 ' 600 ohm, 2.0V DAC mode 'ANALOG_OUT_MODE = %10110 ' 123 ohm, 3.3V DAC mode ANALOG_OUT_MODE = %10111 ' 75 ohm, 2.0V DAC mode SMARTPIN_DAC_MODE = (ANALOG_OUT_MODE << 16) | (INIT_8BIT_DAC_VALUE << 8) | (DIR_MODE << 6) | DAC_MODE SAMPLE_PERIOD = SYSTEM_CLOCK / SAMPLE_RATE 'CPU cycles between sample updates ''Here is the PASM init routine... dat org wrpin SMARTPIN_DAC_MODE, #L_PIN ' Config smartpin DAC mode on "left" pin wrpin SMARTPIN_DAC_MODE, #R_PIN wxpin SAMPLE_PERIOD, #L_PIN ' Set sample period for left audio channel wxpin SAMPLE_PERIOD, #R_PIN ' Set sample period for right audio channel dirh #L_PIN ' Enable smartpin DAC mode on left pin dirh #R_PIN ' Enable smartpin DAC mode on right pin setse1 #%001_000000 | L_PIN ' Event triggered every new sample period (when "left in pin rises") 'mov r1,#128 loop wypin r1, #L_PIN ' Output sample on left channel wypin r1, #R_PIN ' Output sample on right channel 'waitse1 add r1,#1 jmp #loop r1 res 1
Now I coded this.
then p2asm -v33 audio.spin2 ... ok
loadp2 -p /dev/ttyUSB0 audio.bin ... ok (leds P60/P61 flash)
The board is supplied with pc_usb.
The Osci probe is at P0.
but there is no signal.
What am I doing wrong?
I have posted proven DAC testing code from 13 months ago but need to find it. Or I can send it in an hour or two when I am at work
I think you are close to a solution, hang in there!
Hopefully this can be cut back a bit for what you need
I also tried flexgui, and it generates a different error message saying that SMARTPIN_DAC_MODE, SAMPLE_PERIOD, L_PIN and R_PIN are unknown symbols. This is because you use "const" instead of "con" at the beginning of your program. The assembler assume "const" is just a label. PNUT and p2asm start out in the CON mode, so all of the constant definitions work OK in those assemblers. I'm not sure what flexgui does with the constant definitions, but it seems to be ignoring them.
@Tubular, thank's also for the code, next I look what I can use for DAC.
16 kHz sample rate is quite lofi, you could fit 5000 pasm instructions between sample updates @160 MHz. SIDcog takes up to 380 instructions to process each sample. The P2 really has the power to do quite advanced audio processing at high sample rates.
Thank you for the audio_out demo in C.
-- The xor in void audio_out(int value) is very clever ! --
-- I forgot all this tricks. --
I see the first P2 based synthis on the sky;
With inline assembler I was able to do a workaround.
maybe I do a wrong use of getcnt()
//while(getcnt() < stop)//pluck.c:87: warning: signed/unsigned comparison may not work properly //while(getcnt() < (int)stop)//no warning, but duration is sometimes not ok while( tick < stop) //ok,tick come from asm
fastspin -2b pluck.c Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc. Version 4.1.0-beta- Compiled on: Jan 5 2020 pluck.c pluck.p2asm Done. Program size is 2400 bytes
int duration_cycles = 160000 * duration_ms; int start = getcnt(); while( getcnt() - start < duration_cycles)
I played with your code, and added a decay to the notes. You can adjust the decay by changing the value of DECAY_RATE.I can swap the L&R pin definitions in the code and the mono sound channel moves to the other speaker, so I think that means my HW+amp path is working for both channels. The left speaker is working when L=pin6 R=pin7, and the right one is quiet. This swaps when these pins get reversed in the code.
Roger.
EDIT: just looked at the PASM2 in the code in more detail, it was coded for left channel only by the looks of it which explains things.
To get stereo just add this line to the inline asm in both while loops...
wypin sample, #R_PIN