Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
square waves (or pulse waves) 8 Hz duty cycle?
#11
(11-12-2025, 06:28 PM)bplus Wrote: +1 thanks Sam now I know (again) Wink

I am writing it down, now to remember where I put my note...

Hello everybode,

@Petr: Thanks also for the second beautifully programmed listing for creating square waves with qb64.
It works perfect also in the very low frequencys. 
I feel a bit like a spoiled programmer.  Big Grin

In the first listing, I med a small change: Second line CONST T! = 0.3   '100 ms chunks to '300ms chunks???
Reason: In the very low frequencies, I heard a "second click," which disappeared by increasing T! to 0.3.
(Remark: Possible its not the QB64 software but 'the limits' of the hardware board(s) in my PC.)

I might add a program line just before the line with the 'PlayPulsewave' statement: 
if Frequency < 10 then T!=0.3 else T! = 0.1

Rudy
Reply
#12
(11-13-2025, 08:42 AM)Rudy M Wrote: In the first listing, I med a small change: Second line CONST T! = 0.3   '100 ms chunks to '300ms chunks???
Reason: In the very low frequencies, I heard a "second click," which disappeared by increasing T! to 0.3.
(Remark: Possible its not the QB64 software but 'the limits' of the hardware board(s) in my PC.)

I might add a program line just before the line with the 'PlayPulsewave' statement: 
if Frequency < 10 then T!=0.3 else T! = 0.1

Rudy

Yep. T will make PlayPulsewave() send T seconds worth of sample frames to the audio device in one go. You hear the clicks because I made some dumb assumptions. Here, I have updated the demo. This should work much better, and you should not hear the clicks anymore.

Code: (Select All)
OPTION _EXPLICIT

CONST HELP_TEXT = "VOL=" + CHR$(24) + CHR$(179) + CHR$(25) + ", BAL=" + CHR$(27) + CHR$(179) + CHR$(26) + ", DCY=HM" + CHR$(179) + "ED, FRQ=PU" + CHR$(179) + "PD, ESC"

CONST T! = 0.1! ' 100 ms chunks

DIM v AS SINGLE: v = 0.25! ' 25% volume
DIM d AS SINGLE: d = 0.5! ' 50% duty cycle ~ square wave
DIM b AS SINGLE ' center
DIM f AS SINGLE: f = 100 ' Hz
DIM k AS LONG

_CONTROLCHR OFF

DO
    CLS

    PRINT USING "Duty Cycle:  ####%"; d * 100!
    PRINT USING "Volume:      ####%"; v * 100!
    PRINT USING "Balance:    ####"; b * 100!
    PRINT USING "Frequency: ###### Hz"; f
    PRINT
    PRINT HELP_TEXT

    _DISPLAY

    k = _KEYHIT

    SELECT CASE k
        CASE _KEY_UP: v = _MIN(v + 0.01!, 1!)
        CASE _KEY_DOWN: v = _MAX(v - 0.01!, 0!)
        CASE _KEY_LEFT: b = _MAX(b - 0.01!, -1!)
        CASE _KEY_RIGHT: b = _MIN(b + 0.01!, 1!)
        CASE _KEY_HOME: d = _MIN(d + 0.01!, 1!)
        CASE _KEY_END: d = _MAX(d - 0.01!, 0!)
        CASE _KEY_PAGEUP: f = _MIN(f + 3!, 192000!)
        CASE _KEY_PAGEDOWN: f = _MAX(f - 3!, 0!)
        CASE _KEY_ESC: EXIT DO
    END SELECT

    IF _SNDRAWLEN < T THEN PlayPulseWave f, T, d, v, b

    _LIMIT 60
LOOP

_AUTODISPLAY
END

''' @brief Plays a stereo pulse wave for a fixed duration. A STATIC phase accumulator is used so that
''' successive calls continue the wave without an audible click.
''' @param frequencyHz Frequency of the pulse wave in Hz.
''' @param timeSec Duration to play in seconds.
''' @param dutyCycle Duty cycle of the waveform [0..1].
''' @param volume Amplitude of the waveform [0..1].
''' @param pan Stereo pan value (-1 = left, 0 = center, +1 = right).
SUB PlayPulseWave (frequencyHz AS SINGLE, timeSec AS SINGLE, dutyCycle AS SINGLE, volume AS SINGLE, pan AS SINGLE)
    STATIC phase AS SINGLE

    DIM sampleRate AS SINGLE: sampleRate = _MAX(_SNDRATE, 1!)
    DIM samples AS LONG: samples = _MAX(timeSec, 0!) * sampleRate
    DIM duty AS SINGLE: duty = _CLAMP(dutyCycle, 0!, 1!)
    DIM amp AS SINGLE: amp = _CLAMP(volume, 0!, 1!)
    DIM freqStep AS SINGLE: freqStep = _MAX(frequencyHz, 0!) / sampleRate
    DIM panMapped AS SINGLE: panMapped = (_CLAMP(pan, -1!, 1!) + 1!) * _PI(0.25!)
    DIM gainLeft AS SINGLE: gainLeft = COS(panMapped)
    DIM gainRight AS SINGLE: gainRight = SIN(panMapped)
    DIM sample AS SINGLE, i AS LONG

    WHILE i < samples
        phase = phase + freqStep
        IF phase >= 1! THEN phase = phase - INT(phase)

        sample = _IIF(phase < duty, amp, -amp)

        _SNDRAW sample * gainLeft, sample * gainRight

        i = i + 1
    WEND
END SUB
Reply
#13
@a740g,
indeed I do not hear the clicks anymore. Thanks for Your update/correction.
This listing is also interesting because of simple regulation of the duty cycle.
Rudy M
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Is there a square monospace font PhilOfPerth 9 1,714 03-08-2025, 12:26 AM
Last Post: madscijr
  where my square pixels at? James D Jarvis 5 1,186 03-09-2023, 07:04 PM
Last Post: James D Jarvis

Forum Jump:


Users browsing this thread: 1 Guest(s)