_SNDRAW

From QB64 Phoenix Edition Wiki
Revision as of 22:02, 8 September 2025 by RhoSigma (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

The _SNDRAW statement plays sound from a PCM (Pulse Coded Modulation) waveform created by a program.


Syntax

_SNDRAW leftSample[, rightSample][, pipeHandle&]


Parameters

  • The leftSample and rightSample value(s) can be any SINGLE or DOUBLE literal or variable values (samples) in the range -1.0 to 1.0. Each sample specifies a amplitude value. When combined, these values form a curve that represents the shape of the waveform.
  • The pipeHandle& parameter refers to the sound pipe opened using _SNDOPENRAW.


Description

  • Specifying pipeHandle& allows sound to be played through two or more channels at the same time (version 1.000 and up).
  • If only leftSample value is used, the sound will come out of both speakers.
  • _SNDRAW is designed for continuous play. It will not produce any sound until a significant number of samples have been queued. No sound is played if only a few samples are queued. For a one second long sound it needs _SNDRATE samples per channel.
  • Ensure that _SNDRAWLEN is comfortably above 0 (until you've finished playing sound). If you get occasional unintended random clicks, this generally means that _SNDRAWLEN has dropped to 0.
  • _SNDRAW is not intended to queue up many minutes worth of sound. It will probably work but will chew up a lot of memory (and if it gets swapped to disk, your sound could be interrupted abruptly).
  • Do not attempt to use _TIMER or _DELAY or _LIMIT to control the timing of _SNDRAW. You may use them for delays or to limit your program's CPU usage, but how much to queue should only be based on the _SNDRAWLEN.


Availability


Examples

Example 1
Sound using a sine wave with _SNDRAW amplitude * SIN(_PI(2) * duration * (frequency / _SNDRATE))
frequency = 440 'any frequency desired from 36 to 10,000
amplitude = 0.3 'amplitude of the signal from -1.0 to 1.0

FOR duration = 0 TO 5 * _SNDRATE 'play 5 seconds
    _SNDRAW amplitude * SIN(_PI(2) * duration * (frequency / _SNDRATE)) 'sine wave
    '_SNDRAW amplitude * SGN(SIN(_PI(2) * Duration * (frequency / _SNDRATE))) 'square wave
NEXT
_SNDRAWDONE

DO: LOOP WHILE _SNDRAWLEN
END
Explanation
 The loop duration is determined by the number of seconds times the
 _SNDRATE number of samples per second. Square waves can use the
 same formula just enclosed by the SGN function.
Code by DarthWho

Example 2
Similar to the above, but generating different waveforms.
$CONSOLE:ONLY

DIM SHARED SECONDS
DIM SHARED FREQUENCY
DIM SHARED INCREMENT
DIM SHARED AMPLITUDE


SECONDS = 3 ' Duration
FREQUENCY = 170 ' Frequency in Hz

AMPLITUDE = 1 ' Max sample amplitude


PRINT "Sine Wave !"
PRINT SECONDS; " Seconds"
PRINT FREQUENCY; " HZ"
PRINT
sinewave
DO
LOOP WHILE _SNDRAWLEN
PRINT "Square Wave !"
PRINT SECONDS; " Seconds"
PRINT FREQUENCY; " HZ"
PRINT
SquareWave
DO
LOOP WHILE _SNDRAWLEN
PRINT "SawTooth Wave !"
PRINT SECONDS; " Seconds"
PRINT FREQUENCY; " HZ"
PRINT
SawToothWave
DO
LOOP WHILE _SNDRAWLEN

END

SUB sinewave
INCREMENT = (2 * _PI) / (_SNDRATE / FREQUENCY)
FOR sineCount = 1 TO (SECONDS * FREQUENCY)
    ' Loop inside the sine wave (360 degrees)
    FOR inputValue = 0 TO (2 * _PI) STEP INCREMENT
        _SNDRAW AMPLITUDE * SIN(inputValue)
    NEXT inputValue
NEXT sineCount
END SUB


SUB SquareWave
FOR TIME = 1 TO (SECONDS * FREQUENCY)

    FOR I = 1 TO ((_SNDRATE / FREQUENCY) / 2)
        _SNDRAW .75
    NEXT

    FOR I = 1 TO ((_SNDRATE / FREQUENCY) / 2)
        _SNDRAW -.75
    NEXT
NEXT
END SUB

SUB SawToothWave
INCREMENT = 2 / ((_SNDRATE / FREQUENCY) / 2)
DOWNINCREMENT = INCREMENT * -1
FOR TIME = 1 TO (SECONDS * FREQUENCY)

    FOR SAMPLE = (AMPLITUDE * -1) TO AMPLITUDE STEP INCREMENT
        _SNDRAW SAMPLE
    NEXT

    FOR SAMPLE = AMPLITUDE TO (AMPLITUDE * -1) STEP DOWNINCREMENT
        _SNDRAW SAMPLE
    NEXT
NEXT
END SUB
Code by Tony3068

Example 3
A simple ringing bell tone that tapers off.
t = 0
tmp$ = "Sample = ##.#####   Time = ##.#####"
LOCATE 1, 60: PRINT "Rate:"; _SNDRATE
DO
    'queue some sound
    DO WHILE _SNDRAWLEN < 0.2 'you may wish to adjust this
        sample = SIN(t * 440 * ATN(1) * 8) '440Hz sine wave (t * 440 * 2p)
        sample = sample * EXP(-t * 3) 'fade out eliminates clicks after sound
        _SNDRAW sample
        t = t + 1 / _SNDRATE 'sound card sample frequency determines time
    LOOP

    'do other stuff, but it may interrupt sound
    LOCATE 1, 1: PRINT USING tmp$; sample; t
LOOP WHILE t < 3.0 'play for 3 seconds

_SNDRAWDONE
DO WHILE _SNDRAWLEN > 0 'Finish any left over queued sound!
LOOP
END
Code by Artelius

Example 4
Routine uses _SNDRAW to display and play 12 notes from octaves 1 through 9.
DIM SHARED rate&
rate& = _SNDRATE
DO
    PRINT "Enter the octave 1 to 8 (0 quits!):";
    oct% = VAL(INPUT$(1)): PRINT oct%
    IF oct% = 0 THEN EXIT DO
    octave = oct% - 4 '440 is in the 4th octave, 9th note
    COLOR oct% + 1
    PRINT USING "Octave: ##"; oct%
    FOR Note = 0 TO 11 'notes C to B
        fq = FreQ(octave, Note, note$)
        PRINT USING "#####.## \\"; fq, note$
        PlaySound fq
        IF INKEY$ > "" THEN EXIT DO
    NEXT
LOOP
END

FUNCTION FreQ (octave, note, note$)
    FreQ = 440 * 2 ^ (octave + (note + 3) / 12 - 1) '* 12 note octave starts at C (3 notes up)
    note$ = MID$("C C#D D#E F F#G G#A A#B ", note * 2 + 1, 2)
END FUNCTION

SUB PlaySound (frq!) ' plays sine wave fading in and out
    SndLoop! = 0
    DO WHILE SndLoop! < rate&
        _SNDRAW SIN((2 * 4 * ATN(1) * SndLoop! / rate&) * frq!) * EXP(-(SndLoop! / rate&) * 3)
        SndLoop! = SndLoop! + 1
    LOOP
    _SNDRAWDONE
    DO: LOOP WHILE _SNDRAWLEN 'flush the sound playing buffer
END SUB
Code by CodeGuy


See also



Navigation:
Main Page with Articles and Tutorials
Keyword Reference - Alphabetical
Keyword Reference - By usage
Report a broken link