Author: wmb
Date: 2010-01-07 09:04:00 +0100 (Thu, 07 Jan 2010)
New Revision: 1647
Added:
dev/hdaudio/noiseburst.fth
Modified:
dev/geode/ac97/selftest.fth
dev/hdaudio/conexant.fth
dev/hdaudio/core.fth
Log:
HD Audio - improvements to core HD Audio code and preliminary checkin of
noise burst selftest code. That latter needs to be integrated properly.
Modified: dev/geode/ac97/selftest.fth
===================================================================
--- dev/geode/ac97/selftest.fth 2010-01-05 23:22:48 UTC (rev 1646)
+++ dev/geode/ac97/selftest.fth 2010-01-07 08:04:00 UTC (rev 1647)
@@ -45,6 +45,8 @@
/cycle +
;
+\ This version puts the tone first into the left channel for
+\ half the time, then into the right channel for the remainder
: make-tone ( freq -- )
sample-rate to fs ( freq ) set-freq
@@ -64,6 +66,21 @@
/cycle +loop
;
+\ This version puts the tone into both channels simultaneously
+: make-tone2 ( freq -- )
+ sample-rate to fs ( freq ) set-freq
+
+ record-base make-cycle drop
+
+ \ Duplicate left into right in the template
+ record-base #cycle /l* bounds ?do i w@ i wa1+ w! /l +loop
+
+ \ Replicate the template
+ record-base /cycle + record-len /cycle - bounds ?do
+ record-base i /cycle move
+ /cycle +loop
+;
+
: tone ( freq -- )
record-len la1+ " dma-alloc" $call-parent to record-base
make-tone
Modified: dev/hdaudio/conexant.fth
===================================================================
--- dev/hdaudio/conexant.fth 2010-01-05 23:22:48 UTC (rev 1646)
+++ dev/hdaudio/conexant.fth 2010-01-07 08:04:00 UTC (rev 1647)
@@ -4,51 +4,67 @@
\ \ Conexant
-: power-on ( -- ) h# 70500 cmd ;
-: power-off ( -- ) h# 70503 cmd ;
+: power-on ( -- ) h# 70500 cmd ; \ Set power state - on
+: power-off ( -- ) h# 70503 cmd ; \ Set power state - off
: power-on-all ( -- )
" "(01 10 11 12 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24)"
bounds do i c@ to node power-on loop
-;
+;
+: set-node ( node-id -- ) to node ;
+
+: afg ( -- ) 1 set-node ; \ Audio Function Group
+: dac1 ( -- ) h# 10 set-node ;
+: adc1 ( -- ) h# 14 set-node ;
+: mux ( -- ) h# 17 set-node ; \ mux between port b and port c
+: mux2 ( -- ) h# 18 set-node ;
+: porta ( -- ) h# 19 set-node ;
+: portb ( -- ) h# 1a set-node ; \ Port B - OLPC external mic
+: portc ( -- ) h# 1b set-node ; \ Port C - OLPC internal mic
+: portd ( -- ) h# 1c set-node ; \ Port D - OLPC unused
+: porte ( -- ) h# 1d set-node ; \ Port E - OLPC unused
+: portf ( -- ) h# 1e set-node ; \ Port F - OLPC DC input
+: portg ( -- ) h# 1f set-node ; \ Port G - speaker driver
+: porth ( -- ) h# 20 set-node ; \ Port H - S/PDIF out
+: porti ( -- ) h# 22 set-node ; \ Port I - S/PDIF out
+: portj ( -- ) h# 23 set-node ; \ Digital mic
+: vendor ( -- ) h# 25 set-node ; \ Vendor-specific controls
+
: volume-on-all ( -- )
- h# 14 to node h# 36006 cmd h# 35006 cmd
- h# 23 to node h# 36004 cmd h# 35004 cmd
- h# 17 to node h# 3a004 cmd h# 39004 cmd
- h# 18 to node h# 3a004 cmd h# 39004 cmd
- h# 14 to node h# 36200 cmd h# 35200 cmd
- h# 10 to node h# 3a03e cmd h# 3903e cmd
+ adc1 h# 36006 cmd h# 35006 cmd \ Left gain/mute, right gain/mute
+ portj h# 36004 cmd h# 35004 cmd \ Left gain, right gain
+ mux h# 3a004 cmd h# 39004 cmd \ Left gain, right gain
+ mux2 h# 3a004 cmd h# 39004 cmd \ Left gain, right gain
+ adc1 h# 36200 cmd h# 35200 cmd \ Left gain/mute, right gain/mute
+ dac1 h# 3a03e cmd h# 3903e cmd \ Left gain, right gain
;
-h# 1a value mic-in \ Port B
-h# 1b value mic \ Port C
-h# 17 value mux \ mux between the two
-
: pin-sense? ( -- ? ) h# f0900 cmd? h# 8000.0000 and 0<> ;
: set-connection ( n -- ) h# 70100 or cmd ;
: enable-hp-input ( -- ) h# 70721 cmd ;
: disable-hp-input ( -- ) h# 70700 cmd ;
: cx2058x-enable-recording ( -- )
- mic-in to node pin-sense? if
- mux to node 0 set-connection mic-in to node enable-hp-input
+ portb pin-sense? if
+ mux 0 set-connection portb enable-hp-input
else
- mux to node 1 set-connection mic to node enable-hp-input
+ mux 1 set-connection portc enable-hp-input
then
;
: cx2058x-disable-recording ( -- )
- mic-in to node disable-hp-input
- mic to node disable-hp-input
+ portb disable-hp-input
+ portc disable-hp-input
;
: cx2058x-enable-playback ( -- )
- h# 19 to node pin-sense? if \ headphones attached
- h# 1f to node power-off \ turn off speaker
- else \ no headphones
- h# 1f to node power-on \ turn on speaker
- then
- h# 10 to node h# 70640 cmd h# 20000 stream-format or cmd
+ porta pin-sense? if \ headphones attached
+ portg power-off \ turn off speaker
+ else \ no headphones
+ portg power-on \ turn on speaker
+ then
+ dac1 h# 70640 cmd \ 706sc - stream 4, channel 0
+ h# 20000 stream-format or cmd
;
: cx2058x-disable-playback ( -- ) ;
@@ -68,7 +84,7 @@
: unused ( u -- u ) h# 40000000 or ;
: builtin ( u -- u ) h# 80000000 or ;
-: config( ( node -- null-config-default ) to node 0 ;
+: config( ( node -- null-config-default ) 0 ;
: )config ( config-default -- )
\ set the high 24 bits of the config-default value
@@ -78,25 +94,24 @@
8 rshift h# ff and 71f00 or cmd
;
-: port-a ( -- u ) 19 config( 1/8" green left hp-out jack )config ;
-: port-b ( -- u ) 1a config( 1/8" pink left mic-in jack )config ;
-: port-c ( -- u ) 1b config( builtin front mic-in )config ;
-: port-d ( -- u ) 1c config( unused line-out )config ;
-: port-e ( -- u ) 1d config( unused line-out )config ;
-: port-f ( -- u ) 1e config( 1/8" pink left line-in jack )config ;
-: port-g ( -- u ) 1f config( builtin front speaker )config ;
-: port-h ( -- u ) 20 config( unused spdiff-out )config ;
-: port-i ( -- u ) 22 config( unused spdiff-out )config ;
-: port-j ( -- u ) 23 config( unused mic-in )config ;
: config-default ( -- u ) f1c00 cmd? ;
: setup-config-default ( -- )
- port-a port-b port-c port-d port-e port-f port-g port-h port-i port-j
+ porta config( 1/8" green left hp-out jack )config
+ portb config( 1/8" pink left mic-in jack )config
+ portc config( builtin front mic-in )config
+ portd config( unused line-out )config
+ porte config( unused line-out )config
+ portf config( 1/8" pink left line-in jack )config
+ portg config( builtin front speaker )config
+ porth config( unused spdiff-out )config
+ porti config( unused spdiff-out )config
+ portj config( unused mic-in )config
;
: vendor-settings ( -- )
- h# 25 to node
+ vendor
h# 290a8 cmd \ high-pass filter, semi-manual mode, 600Hz cutoff
h# 34001 cmd \ speaker power 1 dB gain
h# 38001 cmd \ over-current / short-circuit protection, 2.6A threshold
@@ -121,7 +136,7 @@
\ Test word to make sure the right settings are configured
: .vendor-settings ( -- )
- h# 25 to node
+ vendor
h# 0a8 h# a9000 check-cmd
h# 001 h# b4000 check-cmd
h# 001 h# b8000 check-cmd
@@ -135,17 +150,15 @@
;
: cx2058x-open ( -- )
- h# 10 to dac
- h# 14 to adc
+ ['] dac1 to with-dac
+ ['] adc1 to with-adc
power-on-all
volume-on-all
vendor-settings
setup-config-default
;
-: cx2058x-close ( -- )
- 1 to node ( function group) power-off
-;
+: cx2058x-close ( -- ) afg power-off ; \ Power off entire Audio Function Group
: cx2058x-init ( -- )
['] cx2058x-open to open-codec
Modified: dev/hdaudio/core.fth
===================================================================
--- dev/hdaudio/core.fth 2010-01-05 23:22:48 UTC (rev 1646)
+++ dev/hdaudio/core.fth 2010-01-07 08:04:00 UTC (rev 1647)
@@ -16,8 +16,8 @@
defer enable-codec-playback ' noop to enable-codec-playback
defer disable-codec-playback ' noop to disable-codec-playback
-0 value dac \ digital to analogue converter node id
-0 value adc \ analogue to digital converter node id
+defer with-dac \ select digital to analogue converter node
+defer with-adc \ select analogue to digital converter node
\ \ DMA setup
@@ -84,6 +84,11 @@
1 value sample-format
2 value #channels
+variable in-stream-format h# 10 in-stream-format ! \ 48kHz 16bit mono
+variable out-stream-format h# 11 out-stream-format ! \ 48kHz 16bit stereo
+
+defer selected-stream-format ' out-stream-format to selected-stream-format
+
: stream-format ( -- u )
sample-base d# 14 lshift ( acc )
sample-mul d# 11 lshift or ( acc )
@@ -92,19 +97,33 @@
#channels 1- or ( fmt )
;
-: sample-rate! ( base mul div ) to sample-div to sample-mul to sample-base ;
+: sample-rate! ( base mul div -- )
+ 8 lshift swap d# 11 lshift or swap d# 14 lshift or ( rate-code )
+ selected-stream-format @ h# ffffff00 invert and or selected-stream-format !
+;
+: sample-width! ( code -- )
+ 4 lshift
+ selected-stream-format @ h# f0 invert and or selected-stream-format !
+;
+: channels! ( #channels -- )
+ 1-
+ selected-stream-format @ h# f invert and or selected-stream-format !
+;
: 48kHz ( -- ) 0 0 0 sample-rate! ;
: 44.1kHz ( -- ) 1 0 0 sample-rate! ;
: 96kHz ( -- ) 0 1 0 sample-rate! ;
: 192kHz ( -- ) 0 3 0 sample-rate! ;
-: 8bit ( -- ) 0 to sample-format ;
-: 16bit ( -- ) 1 to sample-format ;
-: 20bit ( -- ) 2 to sample-format ;
-: 24bit ( -- ) 3 to sample-format ;
-: 32bit ( -- ) 4 to sample-format ;
+: 8bit ( -- ) 0 sample-width! ;
+: 16bit ( -- ) 1 sample-width! ;
+: 20bit ( -- ) 2 sample-width! ;
+: 24bit ( -- ) 3 sample-width! ;
+: 32bit ( -- ) 4 sample-width! ;
+: mono ( -- ) 1 channels! ;
+: stereo ( -- ) 2 channels! ;
+
\ Stream descriptor register interface.
\ There are multiple stream descriptors, each with their own register set.
0 value sd#
@@ -199,7 +218,7 @@
0 0 value codec value node \ current target for commands
-: encode-command ( codec node verb -- )
+: encode-command ( verb -- )
codec d# 28 lshift node d# 20 lshift or or
;
@@ -241,6 +260,7 @@
d# 48.000 value sample-rate
1 value scale-factor
+: upsampling? ( -- ? ) scale-factor 1 <> ;
: low-rate? ( Hz ) dup d# 48.000 < swap d# 44.100 <> and ;
@@ -278,34 +298,69 @@
\ \\ Sound buffer
\ Sample data for playback or recording.
-0 value sound-buffer
-0 value sound-buffer-phys
-0 value /sound-buffer
+0 value in-buffer
+0 value in-buffer-phys
+0 value /in-buffer
-: install-sound-buffer ( adr len -- )
- 2dup to /sound-buffer to sound-buffer
- true dma-map-in to sound-buffer-phys
+0 value out-buffer
+0 value out-buffer-phys
+0 value /out-buffer
+
+: install-in-buffer ( adr len -- )
+ 2dup to /in-buffer to in-buffer
+ true dma-map-in to in-buffer-phys
;
+: release-in-buffer ( -- )
+ in-buffer in-buffer-phys /in-buffer dma-map-out
+;
+
+: install-out-buffer ( adr len -- )
+ 2dup to /out-buffer to out-buffer
+ true dma-map-in to out-buffer-phys
+;
+
+: release-out-buffer ( -- )
+ out-buffer out-buffer-phys /out-buffer dma-map-out
+ \ If we are upsampling, we allocated out-buffer so we need to free it.
+ \ If not, the caller owns out-buffer.
+ upsampling? if out-buffer /out-buffer dma-free then
+;
+
\ Pad buffer: filled with zeros to pad out the end of the stream.
\ (Streams automatically repeat -- this is so we'll have time to stop
\ before that happens.)
-0 value pad-buffer
-0 value pad-buffer-phys
d# 8092 value /pad-buffer
-: alloc-pad-buffer ( -- )
- /pad-buffer dma-alloc to pad-buffer
- pad-buffer /pad-buffer true dma-map-in to pad-buffer-phys
- pad-buffer /pad-buffer 0 fill
+0 value in-pad
+0 value in-pad-phys
+
+: alloc-in-pad ( -- )
+ /pad-buffer dma-alloc to in-pad
+ in-pad /pad-buffer true dma-map-in to in-pad-phys
+ in-pad /pad-buffer 0 fill
;
-: free-pad-buffer ( -- )
- pad-buffer pad-buffer-phys /pad-buffer dma-map-out
- pad-buffer /pad-buffer dma-free
+: free-in-pad ( -- )
+ in-pad in-pad-phys /pad-buffer dma-map-out
+ in-pad /pad-buffer dma-free
;
+0 value out-pad
+0 value out-pad-phys
+
+: alloc-out-pad ( -- )
+ /pad-buffer dma-alloc to out-pad
+ out-pad /pad-buffer true dma-map-in to out-pad-phys
+ out-pad /pad-buffer 0 fill
+;
+
+: free-out-pad ( -- )
+ out-pad out-pad-phys /pad-buffer dma-map-out
+ out-pad /pad-buffer dma-free
+;
+
\ \\ Buffer Descriptor List
struct ( buffer descriptor )
@@ -315,54 +370,71 @@
4 field >bd-ioc
constant /bd
-0 value bdl
-0 value bdl-phys
+: set-buffer-descriptor ( phys uaddr len ioc bd-adr -- )
+ tuck >bd-ioc ! tuck >bd-len ! tuck >bd-uaddr ! >bd-laddr !
+;
+
d# 256 /bd * value /bdl
-: buffer-descriptor ( n -- adr ) /bd * bdl + ;
+0 value in-bdl
+0 value in-bdl-phys
-: allocate-bdl ( -- )
- /bdl dma-alloc to bdl
- bdl /bdl 0 fill
- bdl /bdl true dma-map-in to bdl-phys
+: in-buffer-descriptor ( n -- adr ) /bd * in-bdl + ;
+
+: allocate-in-bdl ( -- )
+ /bdl dma-alloc to in-bdl
+ in-bdl /bdl 0 fill
+ in-bdl /bdl true dma-map-in to in-bdl-phys
;
-: free-bdl ( -- ) bdl bdl-phys /bdl dma-map-out bdl /bdl dma-free ;
+: free-in-bdl ( -- ) in-bdl in-bdl-phys /bdl dma-map-out in-bdl /bdl dma-free ;
-: setup-bdl ( -- )
- allocate-bdl
- sound-buffer-phys 0 buffer-descriptor >bd-laddr ! ( len )
- 0 0 buffer-descriptor >bd-uaddr ! ( len )
- /sound-buffer 0 buffer-descriptor >bd-len ! ( )
- 1 0 buffer-descriptor >bd-ioc !
- \ pad buffer
- alloc-pad-buffer
- pad-buffer-phys 1 buffer-descriptor >bd-laddr !
- 0 1 buffer-descriptor >bd-uaddr !
- /pad-buffer 1 buffer-descriptor >bd-len !
- 0 1 buffer-descriptor >bd-ioc !
+: setup-in-bdl ( -- )
+ allocate-in-bdl
+ in-buffer-phys 0 /in-buffer 1 0 in-buffer-descriptor set-buffer-descriptor
+ alloc-in-pad
+ in-pad-phys 0 /pad-buffer 0 1 in-buffer-descriptor set-buffer-descriptor
;
-: teardown-bdl ( -- )
- free-bdl
- free-pad-buffer
+: teardown-in-bdl ( -- ) free-in-bdl free-in-pad ;
+
+0 value out-bdl
+0 value out-bdl-phys
+
+: out-buffer-descriptor ( n -- adr ) /bd * out-bdl + ;
+
+: allocate-out-bdl ( -- )
+ /bdl dma-alloc to out-bdl
+ out-bdl /bdl 0 fill
+ out-bdl /bdl true dma-map-in to out-bdl-phys
;
+: free-out-bdl ( -- ) out-bdl out-bdl-phys /bdl dma-map-out out-bdl /bdl dma-free ;
+
+: setup-out-bdl ( -- )
+ allocate-out-bdl
+ out-buffer-phys 0 /out-buffer 1 0 out-buffer-descriptor set-buffer-descriptor
+ alloc-out-pad
+ out-pad-phys 0 /pad-buffer 0 1 out-buffer-descriptor set-buffer-descriptor
+;
+
+: teardown-out-bdl ( -- ) free-out-bdl free-out-pad ;
+
\ \\ Stream descriptor (DMA engine)
-: setup-stream ( -- )
+: setup-out-stream ( -- )
reset-stream
- /sound-buffer /pad-buffer + sdcbl rl! \ bytes of stream data
+ /out-buffer /pad-buffer + sdcbl rl! \ bytes of stream data
h# 440000 sdctl rl! \ stream 4
1 sdlvi rw! \ two buffers
1c sdsts rb! \ clear status flags
- bdl-phys sdbdpl rl!
- 0 sdbdpu rl!
- stream-format sdfmt rw!
+ out-bdl-phys sdbdpl rl!
+ 0 sdbdpu rl!
+ out-stream-format @ sdfmt rw!
;
-: stream-done? ( -- ) sdsts c@ 4 and 0<> ;
-: wait-stream-done ( -- ) begin stream-done? until ;
+: stream-done? ( -- ) sdsts c@ 4 and 0<> ;
+: wait-stream-done ( -- ) begin stream-done? until ;
\ \\ Upsampling
@@ -425,52 +497,53 @@
\ \\ Playback
+4 constant out-sd
+
false value playing?
-: upsampling? ( -- ? ) scale-factor 1 <> ;
-
: open-out ( -- )
- 4 to sd#
+ ['] out-stream-format to selected-stream-format
d# 48.000 set-sample-rate
;
+: start-audio-out ( adr len -- )
+ install-out-buffer ( )
+ setup-out-bdl
+ out-sd to sd#
+ setup-out-stream
+ enable-codec-playback
+ start-stream
+ true to playing?
+;
: audio-out ( adr len -- actual )
dup >r
upsampling? if scale-factor upsample then ( adr len )
- install-sound-buffer ( )
- setup-bdl
- setup-stream
- enable-codec-playback
- start-stream
+ start-audio-out
r> ( actual )
;
-: release-sound-buffer ( -- )
- sound-buffer sound-buffer-phys /sound-buffer dma-map-out
- upsampling? if sound-buffer /sound-buffer dma-free then
-;
-
-: (write-done) ( -- )
+: stop-out ( -- )
+ out-sd to sd#
stop-stream
- teardown-bdl
- release-sound-buffer
+ teardown-out-bdl
+ release-out-buffer
uninstall-playback-alarm
+ false to playing?
;
-: write-done ( -- ) wait-stream-done (write-done) ;
+: write-done ( -- ) out-sd to sd# wait-stream-done stop-out ;
: write ( adr len -- actual )
- 4 to sd# audio-out true to playing? install-playback-alarm
+ audio-out install-playback-alarm
;
-: ?end-sound ( -- )
- 4 to sd#
- stream-done? if (write-done) false to playing? then
+: ?end-playing ( -- )
+ out-sd to sd# stream-done? if stop-out then
;
false value stop-lock
: stop-sound ( -- )
true to stop-lock
- playing? if (write-done) false to playing? then
+ playing? if stop-out then
false to stop-lock
;
@@ -478,7 +551,7 @@
: playback-completed-alarm ( -- )
stop-lock if exit then
playing? if
- sd# ?end-sound to sd#
+ ?end-playing
else
\ If playback has already stopped as a result of
\ someone else having waited for completion, we
@@ -492,13 +565,13 @@
: still-playing? ( -- flag )
playing? 0= if false exit then
stop-lock if true exit then
- sd# ?end-sound to sd#
+ ?end-playing
playing?
;
: wait-sound ( -- )
true to stop-lock
- begin playing? while d# 10 ms ?end-sound repeat
+ begin playing? while d# 10 ms ?end-playing repeat
false to stop-lock
;
@@ -506,7 +579,7 @@
false value right-mute?
: set-volume ( dB -- )
- dac to node
+ with-dac
dB>step#
dup left-mute? if h# 80 or then h# 3a000 or cmd \ left gain
right-mute? if h# 80 or then h# 39000 or cmd \ right gain
@@ -514,52 +587,84 @@
\ \\ Recording
+0 constant in-sd
0 value recbuf
0 value recbuf-phys
-d# 65535 value /recbuf
-: open-in ( -- ) d# 48.000 set-sample-rate ;
+: open-in ( -- )
+ ['] in-stream-format to selected-stream-format
+ d# 48.000 set-sample-rate
+;
-: record-stream ( -- )
- 0 to sd#
- 1 to #channels
+: setup-in-stream ( -- )
+ in-sd to sd#
+\ 1 to #channels
reset-stream
- /sound-buffer /pad-buffer + sdcbl rl! \ buffer length
+ /in-buffer /pad-buffer + sdcbl rl! \ buffer length
h# 100000 sdctl rl! \ stream 1, input
1 sdlvi rw! \ two buffers
h# 1c sdsts c! \ clear status flags
- bdl-phys sdbdpl rl!
- 0 sdbdpu rl!
- stream-format sdfmt rw!
- adc to node
- h# 70610 cmd \ stream 1, channel 0
- h# 20000 stream-format or cmd \ stream format
+ in-bdl-phys sdbdpl rl!
+ 0 sdbdpu rl!
+ in-stream-format @ sdfmt rw!
+ with-adc
+ h# 70610 cmd \ 706sc - stream 1, channel 0
+ h# 20000 in-stream-format @ or cmd \ stream format
;
-: audio-in ( adr len -- actual )
- install-sound-buffer ( )
- setup-bdl
- record-stream
+0 value recording?
+: start-audio-in ( adr len -- )
+ install-in-buffer ( )
+ setup-in-bdl
+ setup-in-stream
enable-codec-recording
start-stream
- wait-stream-done
+ true to recording?
+;
+: stop-in ( -- )
+ in-sd is sd#
stop-stream
- release-sound-buffer
- teardown-bdl
- /recbuf
+ teardown-in-bdl
+ release-in-buffer
+ false to recording?
;
+: ?end-recording ( -- )
+ in-sd to sd#
+ stream-done? if stop-in then
+;
+: audio-in ( adr len -- actual )
+ start-audio-in
+ wait-stream-done
+ stop-in
+ /in-buffer
+;
+: out-in ( out-adr out-len in-adr in-len -- )
+ upsampling? if 2swap scale-factor upsample 2swap then ( out-adr,len in-adr,len )
+ start-audio-in ( out-adr out-len )
+ start-audio-out ( )
+ begin
+ recording? if ?end-recording then
+ playing? if ?end-playing then
+ recording? 0= playing? 0= and
+ until
+;
+
: close-in ( -- ) disable-codec-recording ;
+: pbuf " load-base 10000" evaluate ;
+: rbuf " load-base 1meg + 20000" evaluate ;
+: bufs ( -- pbuf,len rbuf,len ) pbuf rbuf ;
+
0 value boost-db
: mic+20db ( -- ) d# 20 to boost-db ;
: mic+0db ( -- ) 0 to boost-db ;
-: set-record-gain ( dB -- ) ; \ adc to node step# input-gain ;
+: set-record-gain ( dB -- ) ; \ with-adc step# input-gain ;
: in-amp-caps ( -- u ) h# f000d cmd? ;
: in-gain-steps ( -- n ) in-amp-caps 8 rshift h# 7f and 1+ ;
-: set-record-gain ( dB -- ) drop ( hardcoded for now ) adc to node h# 40 input-gain ;
+: set-record-gain ( dB -- ) drop ( hardcoded for now ) with-adc h# 40 input-gain ;
\ LICENSE_BEGIN
Added: dev/hdaudio/noiseburst.fth
===================================================================
--- dev/hdaudio/noiseburst.fth (rev 0)
+++ dev/hdaudio/noiseburst.fth 2010-01-07 08:04:00 UTC (rev 1647)
@@ -0,0 +1,486 @@
+.( cross-covariance audio test) cr
+select /audio
+
+code mono-covar ( adr1 adr2 #samples -- d.sum )
+ cx pop
+
+ ax pop \ adr2 in ax
+ bx pop \ adr1 in bx
+ si push
+ di push
+ bp push
+
+ ax si mov
+ bx di mov
+
+ bp bp xor \ Zero accumulator
+ bx bx xor
+
+ begin
+ op: ax lods
+ cwde
+ ax dx mov
+ op: 0 [di] ax mov
+ 2 [di] di lea
+ cwde
+ dx imul
+ ax bx add
+ dx bp adc
+ loopa
+
+ bp ax mov
+
+ bp pop
+ di pop
+ si pop
+
+ bx push
+ ax push
+c;
+code stereo-mono-covar ( stereo-adr1 stereo-adr2 #samples -- d.sum )
+ cx pop
+
+ ax pop \ adr2 in ax
+ bx pop \ adr1 in bx
+ si push
+ di push
+ bp push
+
+ ax si mov
+ bx di mov
+
+ bp bp xor \ Zero accumulator
+ bx bx xor
+
+ begin
+ op: ax lods
+ cwde
+ ax dx mov
+ op: 0 [di] ax mov
+ 4 [di] di lea \ Skip 2 samples for stereo
+ cwde
+ dx imul
+ ax bx add
+ dx bp adc
+ loopa
+
+ bp ax mov
+
+ bp pop
+ di pop
+ si pop
+
+ bx push
+ ax push
+c;
+code stereo-covar ( stereo-adr1 stereo-adr2 #samples -- d.sum )
+ cx pop
+
+ ax pop \ adr2 in ax
+ bx pop \ adr1 in bx
+ si push
+ di push
+ bp push
+
+ ax si mov
+ bx di mov
+
+ bp bp xor \ Zero accumulator
+ bx bx xor
+
+ begin
+ op: ax lods
+ 2 [si] si lea \ Skip other channel sample for stereo
+ cwde
+ ax dx mov
+ op: 0 [di] ax mov
+ 4 [di] di lea \ Skip 2 samples for stereo
+ cwde
+ dx imul
+ ax bx add
+ dx bp adc
+ loopa
+
+ bp ax mov
+
+ bp pop
+ di pop
+ si pop
+
+ bx push
+ ax push
+c;
+code mono-wsum ( adr len -- d.sum )
+ cx pop
+
+ ax pop \ adr in ax
+ si push
+ bp push
+
+ ax si mov
+
+ bp bp xor \ Zero accumulator
+ bx bx xor
+
+ begin
+ op: ax lods
+ cwde
+ cwd \ Actually cdq
+ ax bx add
+ dx bp adc
+ loopa
+
+ bp ax mov
+
+ bp pop
+ si pop
+
+ bx push
+ ax push
+c;
+code stereo-wsum ( adr #samples -- d.sum )
+ cx pop
+
+ ax pop \ adr in ax
+ si push
+ bp push
+
+ ax si mov
+
+ bp bp xor \ Zero accumulator
+ bx bx xor
+
+ begin
+ op: ax lods
+ 2 [si] si lea \ Skip other channel sample for stereo
+ cwde
+ cwd \ Actually cdq
+ ax bx add
+ dx bp adc
+ loopa
+
+ bp ax mov
+
+ bp pop
+ si pop
+
+ bx push
+ ax push
+c;
+: mono-wmean ( adr len -- n )
+ 2/ tuck mono-wsum ( d.sum len )
+ rot m/mod nip ( mean )
+;
+: stereo-wmean ( adr len -- n )
+ 2/ 2/ tuck stereo-wsum ( d.sum len )
+ rot m/mod nip ( mean )
+;
+: -mono-wmean ( adr len -- )
+ 2dup mono-wmean ( adr len mean )
+ -rot bounds ?do ( mean )
+ i <w@ over - h# 7fff min h# -7fff max i w!
+ /w +loop ( mean )
+ drop ( )
+;
+: -stereo-wmean ( adr len -- )
+ 2dup stereo-wmean ( adr len mean )
+ -rot bounds ?do ( mean )
+ i <w@ over - h# 7fff min h# -7fff max i w!
+ /l +loop ( mean )
+ drop ( )
+;
+: lose-6db ( adr len -- )
+ bounds ?do ( )
+ i <w@ 2/ i w! ( )
+ /w +loop ( )
+;
+
+create testarr 100 0 do 0 w, 100 w, loop
+
+create testarr2 100 0 do 0 w, -100 w, loop
+
+: .covar# ( d.covar -- )
+ push-decimal
+ d# 1000000000 m/mod nip 8 .r
+ pop-base
+;
+: .m-covar ( adr1 adr2 len end-start -- )
+ do
+ i 3 u.r space ( adr1 adr2 len )
+ 3dup swap i wa+ swap mono-covar ( adr1 adr2 len d.covar )
+ .covar# cr ( adr1 adr2 len )
+ loop ( adr1 adr2 len )
+ 3drop ( )
+;
+: .sm-covar ( adr1 adr2 len end start -- )
+ do
+ i 3 u.r space ( adr1 adr2 len )
+ 3dup swap i wa+ swap stereo-mono-covar ( adr1 adr2 len d.covar )
+ .covar# cr ( adr1 adr2 len )
+ loop ( adr1 adr2 len )
+ 3drop ( )
+;
+
+0. 2value total-covar
+: sm-covar-sum ( adr1 adr2 len end start -- d.covar )
+ 0. to total-covar
+ do
+ 3dup swap i wa+ swap stereo-mono-covar ( adr1 adr2 len d.covar )
+ total-covar d+ to total-covar ( adr1 adr2 len )
+ loop ( adr1 adr2 len )
+ 3drop ( )
+ total-covar
+;
+: sm-covar-abs-sum ( adr1 adr2 len end start -- d.covar )
+ 0. to total-covar
+ do
+ 3dup swap i wa+ swap stereo-mono-covar ( adr1 adr2 len d.covar )
+ dabs total-covar d+ to total-covar ( adr1 adr2 len )
+ loop ( adr1 adr2 len )
+ 3drop ( )
+ total-covar
+;
+
+: ss-covar-abs-sum ( adr1 adr2 len end start -- d.covar )
+ 0. to total-covar
+ do
+ 3dup swap i la+ swap stereo-covar ( adr1 adr2 len d.covar )
+ dabs total-covar d+ to total-covar ( adr1 adr2 len )
+ loop ( adr1 adr2 len )
+ 3drop ( )
+ total-covar
+;
+
+
+0 value max-index
+0. 2value max-covar
+: mono-covar-max ( adr1 adr2 #samples max-dly min-dly -- index )
+ -1 to max-index ( adr1 adr2 #samples max-dly min-dly )
+ 0. to max-covar ( adr1 adr2 #samples max-dly min-dly )
+
+ do ( adr1 adr2 #samples )
+ 3dup swap i wa+ swap mono-covar ( adr1 adr2 #samples d.covar )
+ dabs ( adr1 adr2 #samples |d.covar| )
+ max-covar 2over d< if ( adr1 adr2 #samples |d.covar| )
+ to max-covar i to max-index ( adr1 adr2 #samples )
+ else ( adr1 adr2 #samples |d.covar| )
+ 2drop ( adr1 adr2 #samples )
+ then ( adr1 adr2 #samples )
+ loop ( adr1 adr2 #samples )
+ 3drop
+ max-index
+;
+: stereo-mono-covar-max ( adr1 adr2 #samples max-dly min-dly -- index )
+ -1 to max-index ( adr1 adr2 #samples max-dly min-dly )
+ 0. to max-covar ( adr1 adr2 #samples max-dly min-dly )
+
+ do ( adr1 adr2 #samples )
+ 3dup swap i wa+ swap stereo-mono-covar ( adr1 adr2 #samples d.covar )
+ dabs ( adr1 adr2 #samples |d.covar| )
+ max-covar 2over d< if ( adr1 adr2 #samples |d.covar| )
+ to max-covar i to max-index ( adr1 adr2 #samples )
+ else ( adr1 adr2 #samples |d.covar| )
+ 2drop ( adr1 adr2 #samples )
+ then ( adr1 adr2 #samples )
+ loop ( adr1 adr2 #samples )
+ 3drop
+ max-index
+;
+: mono-variance ( adr len -- d.variance )
+ >r dup r> 2/ mono-covar
+;
+: left-variance ( adr len -- d.variance )
+ >r dup r> 2/ 2/ stereo-covar
+;
+: right-variance ( adr len -- d.variance )
+ >r wa1+ dup r> 2/ 2/ stereo-covar
+;
+
+h# 40000 value /pb \ Stereo - 10000 is okay for fixter, 40000 is better for case,
+: pb load-base ;
+h# 21000 value /rb \ Mono (stereo for loopback) - 8100 for fixture, 21000 for case,
+: rb load-base 1meg + ;
+
+: random-signal ( -- )
+ pb /pb bounds do random-byte i c! loop
+ pb /pb -stereo-wmean
+ pb wa1+ /pb -stereo-wmean
+ pb /pb lose-6db
+;
+
+: d.. ( -- ) <# # # # # ascii . hold # # # # ascii . hold #s #> type space ;
+: find-max-mono ( -- )
+ pb rb /pb 2 / h# 100 - d# 160 d# 120 mono-covar-max .d max-covar d..
+;
+: find-max-left ( -- )
+ pb rb /pb 4 / h# 100 - d# 160 d# 120 stereo-mono-covar-max .d max-covar d..
+;
+: find-max-right ( -- )
+ pb wa1+ rb /pb 4 / h# 100 - d# 160 d# 120 stereo-mono-covar-max .d max-covar d..
+;
+
+: #samples ( -- n ) /pb 4 / h# 100 - ;
+: left-range ( -- stereo-adr mono-adr #points ) pb rb #samples ;
+: right-range ( -- stereo-adr mono-adr #points ) pb wa1+ rb #samples ;
+: left-stereo-range ( -- stereo-adr mono-adr #points ) pb rb #samples ;
+: right-stereo-range ( -- stereo-adr mono-adr #points ) pb wa1+ rb wa1+ #samples ;
+
+: fixture-analyze-left ( -- )
+ left-range d# 146 d# 141 sm-covar-sum dnegate
+ left-range d# 165 d# 155 sm-covar-sum d+
+ left-range d# 190 d# 180 sm-covar-sum dnegate d+
+ .covar#
+;
+: fixture-analyze-right ( -- )
+ right-range d# 146 d# 141 sm-covar-sum dnegate
+ right-range d# 165 d# 155 sm-covar-sum d+
+ right-range d# 190 d# 180 sm-covar-sum dnegate d+
+ .covar#
+;
+
+\ Reasonable threshold is d# 25
+: fixture-ratio-left ( -- )
+ left-range d# 240 d# 140 sm-covar-abs-sum nip ( sum1 )
+ left-range d# 400 d# 300 sm-covar-abs-sum nip ( sum1 sum2 )
+ d# 10 swap */
+ .d
+;
+: fixture-ratio-right ( -- )
+ right-range d# 240 d# 140 sm-covar-abs-sum nip ( sum1 )
+ right-range d# 400 d# 300 sm-covar-abs-sum nip ( sum1 sum2 )
+ d# 10 swap */
+ .d
+;
+
+\ This compares the total energy within the impulse response band to the
+\ total energy in a similar-length band
+: case-ratio-left ( -- ratio )
+ left-range d# 200 d# 140 sm-covar-abs-sum nip ( sum1.high )
+ left-range d# 540 d# 400 sm-covar-abs-sum nip ( sum1.high sum2.high )
+ d# 10 swap */
+ .d
+;
+: case-ratio-right ( -- ratio )
+ right-range d# 330 d# 140 sm-covar-abs-sum nip ( sum1.high )
+ right-range d# 590 d# 400 sm-covar-abs-sum nip ( sum1.high sum2.high )
+ d# 10 swap */
+ .d
+;
+
+\ This compares the total energy within the impulse response band to the
+\ total energy in a similar-length band
+: loopback-ratio-left ( -- )
+ left-stereo-range d# 148 d# 128 ss-covar-abs-sum nip ( sum1.high )
+ left-stereo-range d# 220 d# 200 ss-covar-abs-sum nip ( sum1.high sum2.high )
+ d# 10 swap */
+ .d
+;
+: loopback-ratio-right ( -- )
+ right-stereo-range d# 148 d# 128 ss-covar-abs-sum nip ( sum1.high )
+ right-stereo-range d# 220 d# 200 ss-covar-abs-sum nip ( sum1.high sum2.high )
+ d# 10 swap */
+ .d
+;
+
+
+d# 1024 /w* buffer: impulse-response
+
+: calc-sm-impulse ( offset -- ) \ offset is 0 for left or 2 for right
+ pb + rb #samples ( adr1 adr2 #samples )
+ d# 1024 0 do
+ 3dup swap i wa+ swap stereo-mono-covar ( adr1 adr2 #samples d.covar )
+ d# 50000000 m/mod nip ( adr1 adr2 #samples n.covar )
+ impulse-response i wa+ w! ( adr1 adr2 #samples )
+ loop ( adr1 adr2 len )
+ 3drop ( )
+;
+: .samples ( adr end start -- )
+ do
+ i push-decimal 3 u.r pop-base ( adr )
+ dup i wa+ <w@ push-decimal 8 .r pop-base cr ( adr )
+ loop ( adr )
+ drop
+;
+d# -23 value test-volume \ d# -23 for test fixture, d# -9 for in-case
+defer rx-channels ' mono is rx-channels \ set to stereo for loopback
+defer analyze-left
+defer analyze-right
+defer fix-dc
+: setup-fixture ( -- )
+ xxx - this needs to use the internal speakers and mic even though the loopback cable is attached
+ ['] mono is rx-channels
+ d# -23 is test-volume
+ h# 20000 to /pb \ Medium burst
+ /pb 2/ h# 1000 + to /rb \ Mono reception (internal mic)
+\ ['] fixture-analyze-left to analyze-left
+\ ['] fixture-analyze-right to analyze-right
+ ['] fixture-ratio-left to analyze-left
+ ['] fixture-ratio-right to analyze-right
+ ['] -mono-wmean to fix-dc
+;
+: setup-case ( -- )
+ xxx - this needs to use the internal speakers and mic even though the loopback cable is attached
+ ['] mono is rx-channels
+ d# -9 is test-volume
+ h# 40000 to /pb \ Long burst for better S/N on far away speaker
+ /pb 2/ h# 1000 + to /rb \ Mono reception (internal mic)
+ ['] case-ratio-left to analyze-left
+ ['] case-ratio-right to analyze-right
+ ['] -mono-wmean to fix-dc
+;
+: setup-loopback ( -- )
+ ['] stereo is rx-channels
+ d# -33 is test-volume
+ h# 10000 to /pb \ Short burst
+ /pb h# 1000 + to /rb \ Stereo reception
+ ['] loopback-ratio-left to analyze-left
+ ['] loopback-ratio-right to analyze-right
+ ['] -stereo-wmean to fix-dc
+;
+: doit ( -- )
+ open-in 48kHz 16bit rx-channels with-adc d# 73 input-gain
+ \ -23 prevents obvious visible clipping
+ open-out 48kHz 16bit stereo test-volume set-volume
+ random-signal
+ lock[ \ Prevent timing jitter due to interrupts
+ pb /pb rb /rb out-in
+ ]unlock
+ rb /rb fix-dc
+\ ." Mono " find-max-mono cr
+\ ." Left " find-max-left cr
+\ ." Right " find-max-right cr
+ analyze-left analyze-right
+;
+
+0 [if]
+: make-tone2 ( freq -- )
+ sample-rate to fs ( freq ) set-freq
+
+ \ Start with everything quiet
+ record-base record-len erase
+
+ record-base make-cycle drop
+
+ \ Duplicate left into right
+ record-base #cycle /l* bounds ?do i w@ i wa1+ w! /l +loop
+
+ \ Replicate the wave template
+ record-base /cycle + record-len /cycle - bounds ?do
+ record-base i /cycle move
+ /cycle +loop
+;
+: freqtest ( frequency -- )
+ open-in 48kHz 16bit mono with-adc d# 73 input-gain
+ \ -23 prevents obvious visible clipping
+ open-out 48kHz 16bit stereo d# -23 set-volume
+
+ pb to record-base /pb to record-len
+ make-tone2
+
+ lock[ \ Prevent timing jitter due to interrupts
+ pb /pb rb /rb out-in
+ ]unlock
+ rb waveform
+;
+[then]
+.( loaded) cr