Nyquist and Plug-Ins

You may find this useful / helpful as a starting point for Nyquist code.
This code can be run in the Nyquist Prompt (https://manual.audacityteam.org/man/nyquist_prompt.html)

In this simple example, there are no stop / start / parity bits, just a direct encoding of list of ones and zeros into an audio waveform.
For practical use it would need some modification, particularly as this will cause a stack overflow if the data is too long. Nevertheless, it should be able to handle a few hundred bits.

For long data, you would need to replace the SEQREP function with a DO loop, and handle I/O without retaining the data in RAM.

To more easily input data, you may want to read the data from a file using READ-BYTE (http://www.cs.cmu.edu/~rbd/doc/nyquist/part19.html#index1742)
More about reading from files here:
https://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/xlisp/xlisp-man/xlisp-man-029.htm
and here:
https://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/xlisp/xlisp-man/xlisp-man-032.htm

See here for the available Nyquist docs: https://wiki.audacityteam.org/wiki/Nyquist_Documentation

;type generate

(setf baud 2205) ;This gives an exactly 20 samples per bit packet.

;Define time to transit between low and high states as
;proportion of bit packet time.
(setf transition 0.3)

;Define signal level as bool t or nil.
(setf state t)

;Binary data as list
(setf data (list 1 1 0 1 0 1 0 0 1 0 1 1 0 1 0 0 0 1 0))

;Total length of a single bit
(setf bitdur (/ 1.0 baud))



(defun rise (dur)
  (setf hz (/ 0.5 dur))
  (osc (hz-to-step hz) dur *sine-table* -90))

(defun fall (dur)
  (setf hz (/ 0.5 dur))
  (osc (hz-to-step hz) dur *sine-table* 90))


;;;Convert transition time to seconds, rounded to exact number of samples
(defun get-transition-dur (dur ratio)
  (let ((ttime (round (* ratio dur *sound-srate*))))
    (/ ttime *sound-srate*)))

;;; Generate binary 1.
;;; 'state' is true/false for current signal level
(defun one ()
  (setf sig (if state one-const one-rise))
  (setf state t)
  sig)

;;; Generate binary 0.
;;; 'state' is true/false for current signal level
(defun zero ()
  (setf sig (if state zero-fall zero-const))
  (setf state nil)
  sig)

(defun add-bit (bit)
  (if (= bit 1) (one) (zero)))


;; We require a different wave shape depending on current state
(setf one-const
  (let ((tdur (get-transition-dur bitdur transition)))
    (snd-const 1 0 *sound-srate* (- bitdur tdur))))

(setf one-rise
  (let ((tdur (get-transition-dur bitdur transition)))
    (seq (rise tdur)
         (cue (snd-const 1 0 *sound-srate* (- bitdur tdur))))))

(setf zero-const
  (let ((tdur (get-transition-dur bitdur transition)))
    (snd-const -1 0 *sound-srate* (- bitdur tdur))))

(setf zero-fall
  (let ((tdur (get-transition-dur bitdur transition)))
    (seq (fall tdur)
         (cue (snd-const -1 0 *sound-srate* (- bitdur tdur))))))


(seqrep (i (length data)) (cue (add-bit (nth i data))))