Alternating Tones

Hi, I need to generate a square wave that alternates between 5 cycles of 600hz, and 4 cycles of 435hz.

I have tried a attempt in MATLAB, however the frequency changes depending on the sample rate.

The resulting wave should look like the picture attached:
WAVE.PNG
Any suggestions?

Thanks,
Elijah

Try this in the Nyquist Prompt effect:

;type generate

;control dur "Duration" float "seconds" 10 0 100
;control gain "Amplitude" float "" 0.8 0 1

;; Generate a square wave that alternates between
;; 5 cycles of 600hz, and 4 cycles of 435 hz.
;;
;; a. Duration of 5 cycles of 600 Hz = 5/600 seconds.
;; b. Duration of 4 cycles of 435 Hz = 4/435 seconds.

;; Hard coded values below could be assigned by ;control lines.
(setf hz-a 600)
(setf cycles-a 5.0)
(setf hz-b 435)
(setf cycles-b 4.0)
(setf step-a (/ cycles-a hz-a))
(setf step-b (/ cycles-b hz-b))
(setf step (+ step-a step-b))


(defun full-cycle ()
  ;; Generate one full cycle of a and b.
  (let ((hz-sig (pwlvr hz-a step-a hz-a 0 hz-b step-b hz-b)))
    (mult gain (osc-pulse hz-sig 0))))

(setf cycles (round (/ dur step)))
; Repeat 'full-cylce' for 'cycles' times.
(seqrep (i cycles) (full-cycle))

Steve, your code works fine. However, the swap rate seems to increase with higher sampling rates. Compare 48000hz vs 192000hz.

Also, the code also make a audible click when switched to a sine wave.

Any fixes?

Thanks,
Elijah

Looks fine to me:



What do you mean? My code doesn’t “switch to a sine wave”. :confused:

Sorry, I meant if I replace the osc-pulse woth hzosc, it makes a clicking noise.

Yes, there will be a slight click each time the “full-cycle” repeats. To avoid that you would need to slide from one frequency to the next rather than jumping from one frequency to the next. It doesn’t matter for square waves because the waveform is at a constant level each time it switches.

Okay, would it be possible to map the frequencies into hzosc?

For example: (hzosc (const 400)) would give 400hz.

Sure. Haven’t you tried it?

You can also do things like this:

(hzosc (mult 20 (sum 100 (hzosc 4))))

I’ve messed with frequency modulation quiet a bit, I was just questioning.

Before, I was just using a square wave to switch the frequencies, however that doesn’t work correctly.

Try this:

;type generate

;control dur "Duration" float "seconds" 10 0 100
;control gain "Amplitude" float "" 0.8 0 1

;; Generate a square wave that alternates between
;; 5 cycles of 600hz, and 4 cycles of 435 hz.
;;
;; a. Duration of 5 cycles of 600 Hz = 5/600 seconds.
;; b. Duration of 4 cycles of 435 Hz = 4/435 seconds.

;; Hard coded values below could be assigned by ;control lines.
(setf hz-a 600)
(setf cycles-a 5.0)
(setf hz-b 435)
(setf cycles-b 4.0)
(setf step-a (/ cycles-a hz-a))
(setf step-b (/ cycles-b hz-b))
(setf step (+ step-a step-b))

; Calculate closest number of complete cycles
(setf cycles (round (/ dur step)))


(defun control-sig ()
  ;; Required breakpoints:
  ;; hz-a, step-a, hz-a, 0, hz-b, step-b, hz-b, 0 ...
  (let ((breakpoints ())
        (cycle (list hz-a step-a hz-a 0 hz-b step-b hz-b 0)))
    (dotimes (i cycles)
      (dolist (c cycle)
        ;; 'push' prepends a value to a list, so we will
        ;; need to reverse the list before we use it.
        ;; Alternatively it could be build it reverse-wise but
        ;;that  makes my head hurt ;-)
        (push c breakpoints)))
    ;(print (reverse breakpoints))
    (pwlvr-list (reverse breakpoints))))


(mult gain (hzosc (control-sig)))

It avoids clicks because the PWL (piecewise linear approximations) functions create a control signal at 1/20th of the sample rate, so there is a short ramp up / down in the frequency rather than an abrupt jump.

or this:

;type generate

;control dur "Duration" float "seconds" 10 0 100
;control gain "Amplitude" float "" 0.8 0 1
;control hz-a "Hz A" int "" 500 100 1000
;control hz-b "Hz B" int "" 435 100 1000
;control cycles-a "Cycles A" int "" 5 1 500
;control cycles-b "Cycles B" int "" 4 1 500

(setf step-a (/ (float cycles-a) hz-a))
(setf step-b (/ (float cycles-b) hz-b))
(setf step (+ step-a step-b))

; Calculate closest number of complete cycles
(setf cycles (round (/ dur step)))


(defun control-sig ()
  ;; Required breakpoints:
  ;; hz-a, step-a, hz-a, 0, hz-b, step-b, hz-b, 0 ...
  (let ((breakpoints ())
        (cycle (list hz-a step-a hz-a 0 hz-b step-b hz-b 0)))
    (dotimes (i cycles)
      (dolist (c cycle)
        (push c breakpoints)))
    (pwlvr-list (reverse breakpoints))))


(mult gain (hzosc (control-sig)))

Alright Steve, this should be the last problem to fix. With your previous code, the swap rate can “fluctuate”, making it sound off…

It took this screenshot of 48,000hz vs 192,000hz.
I made it square wave for clarity.
Capture.PNG

I’m not sure what you are trying to show me.
Are you sure that you are not being mislead by the spectrograms? Note that the spectrograms are calculated in blocks of samples (according to the “window size”. In effect, the “FFT window” is being laid over a periodically changing spectrum, which will create patterns that aren’t really present in the audio (like looking through two net curtains).

I am sure. Try your code on 48,000hz & 192,000hz.

Try alternating between 651hz & 465hz instead of 600&435.

Which code? (I’ve posted several).
What exact settings?
What should I be looking out for?

(In other words, please provide precise steps, what result you expect, and describe precisely in what way the actual result is different.)

This code:


With These settings:
settings.PNG
Low sampling rates vs high sampling rates audibly sound different.
The spectrograms are the same sampling rates, they look different because the code was run at a higher sampling rate for the first track(480,000hz), resampled back to 48000hz, and clipped.


I’m trying to get the output from your code to match the top spectrogram as close as possible.
settings.PNG

The issue is that a cycle of (5 x 651 Hz) + (4 x 465 Hz) cannot be represented exactly at a sample rate of 48000 samples per second, or at the “control rate” of 2400 Hz. The code is rounding all the lengths to exact samples, so there is a repeating pattern of rounding errors on each frequency switch and each cycle. The audible result is that the generated sound is modulated by the sample rates, resulting in lower “beat frequencies”.

Probably the easiest solution is to generate the sounds in a very high sample rate track, then down-sample to the rate you require.

Alright, thanks for the help Steve!