Re: Tones

From: Bob Nash <bob.nash1_at_gmail.com>
Date: Mon, 30 Mar 2009 21:33:07 -0700

Some time ago (1994) I wrote a demo program to demo sounds from the sound
card, including playing a wav file, generating a custom waveform by loading
sound card memory and generating random noise. A long snippet follows
(errors sending the source and executable to your email address). This was
apparently adapted from another (unknown) SF post -- I certainly didn't
figure it out myself :)
REQUIRES RND

LIBRARY WINMM.DLL

6 import: waveInOpen
3 import: waveInPrepareHeader
1 import: waveInStart
1 import: waveInClose
3 import: waveInGetErrorText

6 import: waveOutOpen
3 import: waveOutPrepareHeader
3 import: waveOutWrite
1 import: waveOutClose
3 import: waveOutGetErrorText

1 import: waveOutReset

\ LIBRARY WINMM.DLL
3 import: PlaySound

CREATE TONE-PATH 'FNAME @ ZCOUNT HERE OVER 2+ ALLOT ZPLACE

: ABOUT-SOUND-FILE ( -- z-addr) TONE-PATH ZCOUNT -NAME
   SWAP DUP >R + 0 SWAP C! S" \Ricochet.wav" R@ ZAPPEND R> ;

: play-ricochet ( -- )
   ABOUT-SOUND-FILE ZCOUNT FILE-STATUS NIP 0= IF
      ABOUT-SOUND-FILE 0 SND_FILENAME SND_ASYNC OR PlaySound DROP
   THEN ;

{
-----------------------------------------------------------------------------

This shows how to get buffer-level access to a sound card.
Wave out (to sound card) is demonstrated by outputing a test tone
to your speakers. Wave in is not shown (it is virtually identical to wave
out),
 but comments on how to do it are given.

Note that there are also Winmm.dll API commands to set volume, tone,
in/out device, etc. but they are not covered here. An important
commandset not shown here is the auxGetDevCaps, waveIn and GetDevCaps
commandset. Use them to see what your card can do.

Note that your sound card may not support all formats, and that in some
cases the format is supported only through software translation routines
that run in real time. I don't know how you detect whether a format is
directly
supported by the card or through a software routine, but you can get the
device
ID number from the system when you open the device and that should give
a clue.

Also, inputs from some devices may dictate your format. Your CD player
input,
for example, may only work in the 44.1Ks/s 16 bit stereo mode.

Popular formats are given below. You can see what other formats your
sound card supports by going to your windows sound recorder utility and
looking at recording properties in the file menu.

References: Multimedia section of Windows SDK
             Windows 95 Multimedia and ODBC Bible, Waite group press
             ISBN 1-57169-011-5
 ------------------------------------------------------------------------------
}

\ buffers may be any size as long as they hold an
\ integer number of samples exactly: the larger the buffer the more
efficient
\ your processing can be, but the more latency (delay) you have.
11025 value srate \ sample rate
2 value smplbytes \ number of bytes per sample
srate smplbytes * value bufsize \ a one second buffer at 11025 samples per
second

create wobuf0 bufsize allot \ wave out buffer 0
create wobuf1 bufsize allot \ wave out buffer 1

variable wohndl \ wave out handle

create errbuf 256 allot \ holds an error string if you get one
: woerr? ( result--)
   ?dup if errbuf 255 waveOutGetErrorText drop cr errbuf zcount >tbuf
        then ;

create 1ChPCM-FormatTag \ wave format tag for PCM mono 11025 s/s
     1 h, \ WAVE_FORMAT_PCM from MMREG.H file
               \ There are many formats--WAVE_FORMAT_PCM is pretty much the
               \ only uncompressed format that can be processed directly
               \ by DSP software without translation
     1 h, \ number of channels: typically 1 (mono) or 2 (stereo)
     srate , \ samples per second standard values:11025, 22050, 44100
     srate 2 * , \ ave bytes per sec: samples per second time block
alignment
     2 h, \ block alignment=2 bytes: that is, sixteen bits per (mono)
sample
     smplbytes 8 * h, \ bits per sample
     0 h, \ extra info

\ CD quality is 2 channel, 16 bit 44100 s/s with byte alignment of 4

\ This format is normally the lowest rate you can get from the system:
\ 8000 s/s 8 bit sample (u-law compressed--must be uncompressed for DSP
processing)
\ mono
{ create ulaw-FormatTag \ wave format tag for mono u-law, 8Ksps
     7 h, \ WAVE_FORMAT_MULAW from MMREG.H file
     1 h, \ number of channels
     8000 , \ samples per second
     8000 , \ ave bytes per sec
     1 h, \ block alignment=byte
     8 h, \ bits per sample
     0 h, \ extra info
}

\ each buffer requires a header structure: this structure is used to
register
\ the buffer with the system
create wohdr0 \ header to process blocks
wobuf0 , \ address of buffer
bufsize , \ length
0 , \ bytes played, not used
0 , \ user data, not used
0 , \ flags
0 , \ number of loops
0 , \ pointer to wave header tag struct--filled in by winders
0 , \ xtra
\ 32 bytes total

create wohdr1 \ header to process blocks
wobuf1 , \ address of buffer
bufsize , \ length
0 , \ bytes recorded, not used
0 , \ user data, not used
0 , \ flags
0 , \ number of loops
0 , \ pointer to wave header tag struct--filled in by winders
0 , \ xtra
\ 32 bytes total

\ Here is where your DSP routine goes. We will simply put a
\ squarewave test tone into the buffer
10000 value amplitude \ PCM systems all seem to use signed integers, either
8 or 16 bits.
0 value smplcount \ counts samples till toggle of amplitude
\ 6 value frequency \ output frequency=srate/(2*frequency)
12 value frequency \ output frequency=srate/(2*frequency)

: !amplitude ( -- ) amplitude RND [ amplitude 2 / ] LITERAL MAX TO
amplitude ;

: squarewave1 ( addr--) \ assumes 2 bytes/sample -- random tones
    80 RND 1+ TO frequency \ random frequency
    dup bufsize + swap do
                amplitude i h!
                1 +to smplcount smplcount frequency < not if
                   0 to smplcount amplitude negate to amplitude
                then
              2 +loop ;

: squarewave2 ( addr--) \ assumes 2 bytes/sample -- raspy sound
    dup bufsize + swap do
                amplitude DUP 0< IF NEGATE THEN RND i h!
                1 +to smplcount smplcount frequency < not if
                   0 to smplcount amplitude negate to amplitude
                then
              2 +loop ;

: squarewave3 ( addr--) \ assumes 2 bytes/sample -- another raspy sound
    dup bufsize + swap do
                amplitude RND i h!
                1 +to smplcount smplcount frequency < not if
                   0 to smplcount amplitude negate to amplitude
                then
              2 +loop ;

: squarewave4 ( adr -- ) \ combo sounds
   !amplitude
   6 RND 1+ 2 > IF
                   squarewave1
                ELSE
                   2 RND IF squarewave2 ELSE squarewave3 THEN
                THEN ;

1 VALUE TCHOICE

[SWITCH TONE-CHOICE ZERO ( Key-Code - res)
   1 RUN: squarewave1 ;
   2 RUN: squarewave2 ;
   3 RUN: squarewave3 ;
   4 RUN: squarewave4 ;
SWITCH]

: squarewave ( adr -- ) ( 3 RND 1+ TONE-CHOICE) TCHOICE TONE-CHOICE ;

{
==============================================================================================
\ When opening the device, we must specify how we will handle device events:
\ the common event will be that a buffer has been filled (on wavein)
\ or emptied (on waveout). Here we tack the event handler to Swiftforth's
\ console window message handler. We give the DLL the window handle and tell
\ it that it is a window handle.

console-window +order \ reopen the console window package
[+switch sf-messages
         MM_WOM_DONE run: lparam @ squarewave \ buffer released: fill with
new data
                          wohndl @ lparam 32 waveOutWrite drop 0 ; \ and
reregister buffer
         \ wparam has the device handle, but we use our own (see QUIET
below)
  switch]
console-window -order
 ================================================================================================
}

: TONE ( --) \ start the sound
  \ open the device
    wohndl \ address of handle
    WAVE_MAPPER \ device ID. WAVE_MAPPER allows the system to select any
supporting device
    1ChPCM-FormatTag \ format structure above
    hwnd \ sf window handle
    0 CALLBACK_WINDOW \ callback is a window handle
    WaveOutOpen woerr? \ the handle is in the wohndl variable now.
  \ prepare the buffers
    wohndl @ wohdr0 32 waveOutPrepareHeader drop
    wohndl @ wohdr1 32 waveOutPrepareHeader drop
  \ fill buffers with intial data
    wobuf0 squarewave
    wobuf1 squarewave
  \ register them. This starts the tone going
    wohndl @ wohdr0 32 waveOutwrite woerr?
    wohndl @ wohdr1 32 waveOutWrite woerr?
    ;

: QUIET
   wohndl @ 0 wohndl ! \ by putting zero in the handle, the callback
                       \ buffer reregister will fail.
    \ we do this because we cannot close the device until all buffers are
played
    \ or are reset by the command below.
   dup waveOutReset woerr? \ aborts playback and sends a buffer empty
message for each registered buffer
   waveOutClose woerr? ;

{ ----- wavein: -----
  wavein uses the same procedure as waveOut except waveIn commands are used:
  setup buffers, setup format structure, prepare headers, open the device
and register the buffers.
  The same message is used by the system, but now it means the buffer is
full instead of empty.
 --------------------- }

{ -----------------------------[ TONE REFRESH ]--------------------------- }

20000 TASK TONIO
150 CONSTANT #TONE

: snooze ( -- ) #TONE RND 10 + Sleep DROP ;

: TONE-TASK
   TONIO ACTIVATE BEGIN
      100 RND 1+ 40 > IF
         TONE snooze QUIET
      ELSE
         play-ricochet snooze
      THEN
   AGAIN ;

On Mon, Mar 30, 2009 at 11:53 AM, Roger Dube <rogerdube_at_dathq.com> wrote:

> Has anyone been able to generate a tone within Swiftforth? I tried beep,
> but
> the PC speaker just gives a łthunk˛ that doesnąt change frequency with
> input
> parameters (I expected it to respond to łfrequency duration BEEP˛ but it
> doesnąt change tone.
> Thanks -
>
> Roger
> --
> Dr. Roger Dube
> President/Chief Scientist
> Digital Authentication Technologies, Inc.
>
> 561.392.7404 (office)
>
> 561.892.2474 (eFax)
>
> RogerDube_at_datHQ.com
>
> 690 Yamato Road Suite 4 - #210
>
> Boca Raton, FL 33431
>
>
>
> ----------------------------------------------------------------------
> sftalk_at_forth.com The SwiftForth programming discussion email list
> To unsubscribe, send subject "unsubscribe" to sftalk-request_at_forth.com
> For list command help, send subject "help" to sftalk-request_at_forth.com
> Message archives are located at http://www.forth.com/archive/sftalk
> ----------------------------------------------------------------------
> This list is a forum for SwiftForth users. For product support and
> bug reports, please send email to support_at_forth.com
> ----------------------------------------------------------------------
>
>

----------------------------------------------------------------------
sftalk_at_forth.com The SwiftForth programming discussion email list
To unsubscribe, send subject "unsubscribe" to sftalk-request_at_forth.com
For list command help, send subject "help" to sftalk-request_at_forth.com
Message archives are located at http://www.forth.com/archive/sftalk
----------------------------------------------------------------------
This list is a forum for SwiftForth users. For product support and
bug reports, please send email to support_at_forth.com
----------------------------------------------------------------------
Received on Mon Mar 30 2009 - 21:33:58 PDT


Subscribe to our e-mail list service. It's free for all SwiftForth and SwiftX users!

This archive was generated 09-Feb-2012. Archive updated nightly.