[OpenBIOS] r369 - cpu/x86 dev/geode/ac97

svn at openbios.org svn at openbios.org
Wed May 9 20:43:00 CEST 2007


Author: wmb
Date: 2007-05-09 20:42:59 +0200 (Wed, 09 May 2007)
New Revision: 369

Modified:
   cpu/x86/adpcm.fth
   dev/geode/ac97/selftest.fth
Log:
Audio support for non-compressed wav files.


Modified: cpu/x86/adpcm.fth
===================================================================
--- cpu/x86/adpcm.fth	2007-05-09 18:42:03 UTC (rev 368)
+++ cpu/x86/adpcm.fth	2007-05-09 18:42:59 UTC (rev 369)
@@ -1,6 +1,13 @@
 \ See license at end of file
 purpose: decode IMA/DVI ADPCM .wav file
 
+2 value #output-ch                      \ Number of output channels
+0 value audio-ih                        \ /audio ihandle
+0 value /pcm-output                     \ Size of uncompressed buffer
+defer (play-pcm)
+
+: $call-audio  ( ... method -- ... )  audio-ih $call-method  ;
+
 \ Uncompressed data format:
 \   16-bit Left, 16-bit Right, ...
 \
@@ -107,7 +114,7 @@
 ;
 
 : adpcm-decode-blk  ( in out #sample -- )
-   #ch 0  ?do                           ( in out #sample )
+   #ch #output-ch min 0  ?do            ( in out #sample )
       2 pick i /l * +                   ( in out #sample in' )
       2 pick i /w * +                   ( in out #sample in out' )
       init-ch-vars			( in out #sample in' out' )
@@ -121,20 +128,20 @@
    stepsize-table to 'stepsize-table
 
    dup to blk-size                      ( in out #sample #ch blk-size )
-   over 4 * - 1+ to #sample/blk         ( in out #sample #ch )
+   over 4 * - 2* over / 1+ to #sample/blk ( in out #sample #ch )
    dup to #ch                           ( in out #sample #ch )
-   dup /l * to in-skip                  ( in out #sample #ch )
-       /w * to out-skip                 ( in out #sample )
+   /l * to in-skip                      ( in out #sample )
+   #output-ch /w * to out-skip          ( in out #sample )
 
    begin  dup 0>  while                 ( in out #sample )
       3dup #sample/blk min adpcm-decode-blk
       rot blk-size +                    ( out #sample in' )
-      rot #sample/blk #ch * wa+         ( #sample in out' )
+      rot #sample/blk #output-ch * wa+  ( #sample in out' )
       rot #sample/blk -                 ( in out #sample' )
    repeat  3drop
 ;
 
-\ Decode an .wav file
+\ Decode a .wav file
 \
 \ .wav file format:
 \ "RIFF" L<len of file> "WAVE"
@@ -148,6 +155,26 @@
 \        W<sample> B<index> B<0> per channel
 \        (block size - 1) samples of compressed data
 
+0 value wav-fmt-adr
+0 value wav-fact-adr
+0 value wav-data-adr
+
+: .wav-cc  ( cc -- )
+   case
+          0  of  ." unknown"           endof
+          1  of  ." PCM"               endof
+          2  of  ." MS ADPCM"          endof
+          6  of  ." ITU G.711 a-law"   endof
+          7  of  ." ITU G.711 au-law"  endof
+      h# 11  of  ." IMA ADPCM"         endof
+      h# 16  of  ." ITU G.723 ADPCM"   endof
+      h# 31  of  ." GSM 6.10"          endof
+      h# 40  of  ." ITU G.721 ADPCM"   endof
+      h# 50  of  ." MPEG"              endof
+      ( default )  ." unknown code: " dup u.
+   endcase
+;
+
 : find-wav-chunk?  ( in chunk$ -- in' true | false )
    rot dup 4 + le-l@ over + swap h# c + ( chunk$ in-end in' )
    begin  2dup u>  while                ( chunk$ in-end in )
@@ -163,43 +190,111 @@
    dup " RIFF" comp  swap 8 + " WAVE" comp  or 0=
 ;
 
-: fmt-ok?  ( in -- #ch blk-size true | false )
-   " fmt " find-wav-chunk? 0=  if  false exit  then   ( in' )
-   dup      8 + le-w@ h# 11 =              \ compression code: DVI_ADPCM
-   over h# 16 + le-w@     4 = and  if      \ bits/sample
-      dup   h#  a + le-w@                  ( #ch )
-      swap  h# 14 + le-w@  true            ( #ch blk-size true )
+: parse-wav-ok?  ( in -- ok? )
+   0 to wav-fmt-adr  0 to wav-fact-adr  0 to wav-data-adr
+   dup wav-ok? 0=  if  drop false exit  then
+   dup " fmt " find-wav-chunk?  if  to wav-fmt-adr  then
+   dup " fact" find-wav-chunk?  if  to wav-fact-adr  then
+   " data" find-wav-chunk?  if  8 + to wav-data-adr  then
+   wav-fmt-adr 0= wav-data-adr 0= or not
+;
+
+: wav-cc        ( -- cc )        wav-fmt-adr  dup  if      8 + le-w@  then  ;
+: wav-in-#ch    ( -- #ch )       wav-fmt-adr  dup  if  h#  a + le-w@  then  ;
+: wav-#sample   ( -- #sample )   wav-fact-adr dup  if      8 + le-l@  then  ;
+: wav-blk-size  ( -- blk-size )  wav-fmt-adr  dup  if  h# 14 + le-w@  then  ;
+
+: set-sample-rate  ( -- )
+   wav-fmt-adr ?dup  if  h# c + le-l@ " set-sample-rate" $call-audio  then
+;
+
+0 value out-move
+: condense-pcm  ( adr -- )
+   wav-in-#ch #output-ch - /w * to in-skip
+   #output-ch /w * to out-move
+   dup dup 4 - le-l@  bounds  ?do          ( out )
+      i over out-move move                 ( out )
+      out-move +                           ( out' )
+   in-skip +loop  drop                     ( )
+;
+: expand-pcm  ( adr -- )
+   #output-ch wav-in-#ch - /w * to out-skip
+   wav-in-#ch /w * to out-move
+   dup dup 4 - le-l@  bounds  swap out-move -  ( out in-begin in-end )
+   begin  2dup u<  while                   ( out in-begin in )
+      dup 3 pick out-move move             ( out in-begin in )
+      out-move - rot out-move + -rot       ( out' in-begin in' )
+      2 pick out-skip erase                ( out in-begin in )
+      rot out-skip + -rot                  ( out' in-begin in )
+   repeat  3drop                           ( )
+;
+
+: play-pcm-once  ( adr len -- )  " write" $call-audio drop " write-done" $call-audio  ;
+: play-pcm-loop  ( adr len -- )
+   ." Press a key to abort" cr
+   begin  2dup play-pcm-once  key?  until  key drop  2drop
+;
+' play-pcm-once to (play-pcm)
+
+: play-pcm  ( adr -- error? )
+   wav-in-#ch 0=  if  drop true exit  then
+   set-sample-rate
+   wav-data-adr 4 - le-l@ to /pcm-output
+   wav-in-#ch #output-ch =  if
+      /pcm-output (play-pcm)                 \ Play straight from the source
    else
-      drop false                           ( false )
-   then
+   /pcm-output wav-in-#ch / #output-ch * to /pcm-output
+   #output-ch wav-in-#ch <  if
+      dup condense-pcm                       \ Skip extra channel data
+      /pcm-output (play-pcm)
+   else
+      dup expand-pcm                         \ Convert mono to stereo
+      /pcm-output (play-pcm)
+   then  then
+   false
 ;
 
-: fact-ok?  ( in -- #sample true | false )
-   " fact" find-wav-chunk? dup  if  swap 8 + le-l@ swap  then
+: play-ima-adpcm  ( adr -- error? )
+   wav-fact-adr 0=  if  drop true exit  then
+   set-sample-rate
+   wav-#sample #output-ch * /w * to /pcm-output
+   \ Because alloc-mem does not guarantee contiguous physical memory, use load-base area.
+   loaded + pagesize round-up tuck          ( out in out )
+   dup /pcm-output erase                    ( out in out )
+   wav-#sample wav-in-#ch wav-blk-size      ( out in out #sample #ch blk-size )
+   adpcm-decoder                            ( out )
+   /pcm-output (play-pcm)                   ( )
+   false                                    ( error? )
 ;
 
-: data-ok?  ( in -- in' true | false )
-   " data" find-wav-chunk? dup  if  swap 8 + swap  then
+: (play-wav)  ( adr -- error? )
+   parse-wav-ok?  not  if  ." Not a .wav file" cr true exit  then
+   " /audio" open-dev ?dup 0=  if  ." Cannot open audio device" cr true exit  then
+   to audio-ih
+   wav-cc  case
+          1  of  wav-data-adr play-pcm        endof
+      h# 11  of  wav-data-adr play-ima-adpcm  endof
+      ( default )  ." Cannot play .wav format type: " dup .wav-cc true swap cr
+   endcase
+   audio-ih close-dev
 ;
 
-: adpcm-decode  ( in out -- actual )
-   over wav-ok? not  if  2drop 0 exit  then       ( in out )
-   swap dup data-ok? not  if  2drop 0 exit  then  ( out in in' )
-   -rot dup fact-ok? not  if  3drop 0 exit  then  ( in' out in #sample )
-   swap     fmt-ok?  not  if  3drop 0 exit  then  ( in' out #sample #ch blk-size )
-   2 pick 2 pick /w * * >r                        ( in' out #sample #ch blk-size )  ( R: actual )
-   adpcm-decoder r>                               ( actual )
+: ($play-wav)  ( file-str -- )
+   boot-read
+   load-base (play-wav)  abort" Error playing wav file"
 ;
 
-: adpcm-size  ( in -- actual )
-   dup  wav-ok?  not  if  drop 0 exit  then       ( in )
-   dup  fact-ok? not  if  drop 0 exit  then       ( in #sample )
-   swap fmt-ok?  not  if  drop 0 exit  then       ( #sample #ch blk-size )
-   drop /w * *                                    ( actual )
+: $play-wav  ( file-str -- )  ['] play-pcm-once to (play-pcm)  ($play-wav)  ;
+: play-wav  ( "filename< >" -- )  safe-parse-word $play-wav  ;
+
+: $play-wav-loop  ( file-str -- )
+   ['] play-pcm-loop to (play-pcm)
+   ($play-wav)
 ;
+: play-wav-loop  ( "filename< >" -- )  safe-parse-word $play-wav-loop  ;
 
 \ LICENSE_BEGIN
-\ Copyright (c) 2007 FirmWorks
+\ Copyright (c) 2006 FirmWorks
 \ 
 \ Permission is hereby granted, free of charge, to any person obtaining
 \ a copy of this software and associated documentation files (the

Modified: dev/geode/ac97/selftest.fth
===================================================================
--- dev/geode/ac97/selftest.fth	2007-05-09 18:42:03 UTC (rev 368)
+++ dev/geode/ac97/selftest.fth	2007-05-09 18:42:59 UTC (rev 369)
@@ -109,32 +109,7 @@
 
 : ?play-wav-file  ( -- )
    selftest-args dup 0=  if  2drop exit  then
-
-   \ Read the .wav file
-   2dup ." Play " type cr
-   " boot-read" evaluate
-
-   \ Allocate raw audio buffer
-   " loaded" evaluate 0=  if  drop exit  then         \ No data loaded
-   " adpcm-size" evaluate                 ( /raw-buf )
-   ?dup 0=  if  exit  then                \ Not an IMA ADPCM .wav file
-   dup to /raw-buf alloc-mem to raw-buf   ( )
-
-   \ Decode the .wav file
-   " load-base" evaluate                  ( in )
-   raw-buf " adpcm-decode" evaluate       ( /raw-buf )  ( R: len wav-buf )
-   ?dup 0=  if  exit  then                \ Not an IMA ADPCM .wav file
-
-   \ Play the raw audio data
-   ." Press a key to abort" cr
-   open-out  plevel set-pcm-gain  glevel h# 38 codec! 
-   begin
-      raw-buf /raw-buf audio-out drop
-   key?  until  write-done
-   key drop
-
-   \ Release the raw audio buffer
-   raw-buf /raw-buf free-mem  0 to raw-buf 0 to /raw-buf
+   " $play-wav-loop" $find 0=  if  2drop  else  catch drop  then
 ;
 
 : selftest  ( -- error? )




More information about the OpenBIOS mailing list