problem with SAL

To set the value of a variable you need to use one of the “SET” functions, for example:

(setq vibamp 0.1)

In the above command:

  • SETQ is the function.
  • VIBAMP and 0.1 are the arguments.
  • The two arguments for SETQ are the “variable” (a symbol) and the “value”.
  • VIBAMP is the variable.
  • 0.1 is the value

Thus, (setq vibamp 0.1) sets the value of vibamp to 0.1.

Nyquist is based on XLISP (a version of LISP).
Two documents that you will find very useful are the XLISP manual (XLISP: An Object-oriented Lisp) and the XLISP Language Reference (XLISP Language Reference).

The XLISP Language Reference is particularly useful for looking up the correct syntax for XLISP commands, for example:
SETQ XLISP setq
This shows that the function SETQ takes pairs of arguments. Each pair of arguments consists of a symbol (the variable) followed by a value.
Thus:

(setq A 1 B 2 C 3)

sets “A” to a value of 1, “B” to a value of 2, and “C” to a value of 3.

Hello sir.
I moved forward in the understanding of the variable vibamp. This variable corresponds to the amplitude of the vibrato. The amplitude is expressed as a ratio of the frequency of the fundamental of the sound. If vibamp is equal to 1, the frequency of the fundamental oscillates between -50 % and +50 % of the initial value.
In this case, the value of vibamp is 0.01; thus the frequency of the fundamental should oscillate between -0.5 % and +0.5 %.
Thus my question is the following one; how can we define a ratio of a frequency?
Beforehand thank you for your help.

I’m not sure that I understand your question.

A ratio can be expressed as a number value (example: 0.6), as the relationship of two values (example: 6:10), as a percentage (example: 60%), or as a fraction (example: 6/10). In programming it is often convenient to express a ratio as a single value. Thus a ratio of 6:10 = 6/10 = 0.6.
So if we have a variable called “my-ratio” and we want it to express the ratio 6:10, we would simply set the value of “my-ratio” to 0.6

(setq my-ratio 0.6)

I thank you.
In fact, why I try to make understand to Nyquist which is the ratio, it is because the code which I wrote does not still work. i wrote:

(setq vibamp 0.01)
(setq lfo 6)

(defun vibtone (pitch vibamp)
(mult  (fmosc (step-to-hz pitch) vibamp lfo) (*saw-table*)))

(vibtone E4 5)

The Nyquist prompt indicates: error: bad argument type - 5
Function: #<Subr-SND-SRATE: #76189c8>
Arguments:
1
Function: #<FSubr-LET: #7614a78>
Arguments:
((MODULATION-SRATE (SND-SRATE MODULATION)) (HZ (STEP-TO-HZ (+ PITCH (GET-TRANSPOSE)))))
(COND ((< SOUND-SRATE MODULATION-SRATE) (FORMAT T “Warning: down-sampling FM modulation in fmosc~%”) (SETF MODULATION (SND-DOWN SOUND-SRATE MODULATION))))
(COND ((> HZ (/ SOUND-SRATE 2)) (FORMAT T “Warning: fmosc nominal frequency (~A hz) will alias at current sample rate (~A hz).n” HZ SOUND-SRATE)))
(SCALE-DB (GET-LOUD) (SND-FMOSC (CAR SOUND) (CADR SOUND) SOUND-SRATE HZ (LOCAL-TO-GLOBAL 0) MODULATION PHASE))
Function: #<Closure-FMOSC: #74ee5d0>
Arguments:
329.628
1
6
Function: #<Closure-VIBTONE: #7614368>
Arguments:
64
1
1>
By reading, this error message, it seems to me that it comes because the variable ( vibamp ) is not enough precise in my code. Does the problem in my code come because the ratio is not specified?

You are using the function “fmosc
What arguments are you passing to that function?

Hello sir.
It seems to me that fmosc has 3 arguments: (step-to-hz pitch), vibamp and lfo. The pitch has for value E4 or 64. Vibamp has for value 0.01. lfo has for value 6;

It gets worse instead of better, if I may say so…
Fmosc takes min. 2 arguments:

  • a pitch expressed as a midi note.
    As I said above the ‘step-to-hz’ function is wrong you’ve already have a pitch as step (e.g. E6) and that’s what the function needs.
  • a modulating sound -not a number (Lfo is in your code defined as number).
    The sound is made with the lfo function - which takes Hz as a parameter.
    It’s Amplitude is always 1. Therefore, we must multiply this sound with vibamp (which is a little small, the tone will only vibrate within a 1/100 Hz, barely audible).
    So it should be something like this:
(defun vibtone (pitch vibamp freq)
  (fmosc pitch (mult vibamp (lfo freq *saw-table*))))
;;
(vibtone e6 0.5 6.0)

The 3 variables that we pass to the function (or better, the numeric values) are connected with 3 different functions:
Pitch → (fmosc …)
vibamp → (mult …)
freq → (lfo …)

Basically the same as Robert has written…

fmosc takes two arguments and two optional arguments:
(fmosc pitch modulation [table phase])
The square brackets indicate that the enclosed arguments are optional, so you can use any of:
(fmosc pitch modulation)
(fmosc pitch modulation table)
(fmosc pitch modulation table phase)

Note that the first argument is “pitch” and not “frequency”, therefore your pitch value “pitch” (E4) should not be converted to Hz.

You wrote:

(fmosc (step-to-hz pitch) vibamp lfo)

so if we take out the “step-to-hz” conversion, that gives:

(fmosc pitch vibamp lfo)

but what is that third argument? You have written “lfo” as the third argument as if “lfo” was a variable and an argument of fmosc.

Then you multiply the result by (saw-table)

(mult (fmosc ...) (*saw-table*)

You have written "saw-table* in brackets, so Nyquist will try to interpret that as a function, but (saw-table) is not defined anywhere as a function. saw-table (no brackets) is defined in Nyquist as a global variable. The value of saw-table is one of the pre-defined look-up tables that is created by Nyquist http://www.cs.cmu.edu/~rbd/doc/nyquist/part2.html#index16

As Robert wrote, saw-table should be an argument of the function lfo.
The syntax for the function lfo is:
(lfo freq [duration table phase])
(I’m not sure why the manual does not show the square brackets - I think that is a misprint - duration, table and phase are optional arguments of lfo.
So Robert’s code is not quite right because he has missed out the optional “duration” argument before the optional “table” argument.

Going back to the original SAL code:

define function vibtone(pitch, vibamp)
  return fmosc(pitch,
               step-to-hz(pitch) * vibamp * 0.01 * lfo(6),
               *saw-table*)

play vibtone(e5, 5)

we see that the function fmosc is given three arguments; “pitch”, a complex expression, and “saw-table
So a partial translation into LISP would be:

(fmosc pitch
       (complex-expression)
       *saw-table*)

where “complex-expression” is defined as:

; SAL
step-to-hz(pitch) * vibamp * 0.01 * lfo(6)

; LISP
(mult (step-to-hz pitch) vibamp 0.01 (lfo 6))

Putting this all together:

(defun vibtone (pitch vibamp)
  (fmosc pitch
         (mult (step-to-hz pitch) vibamp 0.01 (lfo 6))
         *saw-table*))

(vibtone E4 5)

Sorry that I’ve forgot the duration in ‘LFO’.
I often use the high resolution counterpart ‘hzosc’ and this function doesn’t need the duration argument.

Hello Sirs. I work on the following code:

set modstep = hz-to-step((3.0 / 5.0) * step-to-hz(c4))
play fmosc(c4, pwl(1, 4000, 1) * osc(modstep)) ~ 10

This code generates a wave where appears a harmonic scanning.
I wrote:

 (setq modstep (eql
(hz-to-step (/ 3.0 5.0)) (step-to-hz C4) ))

(defun mytone ()
  (fmosc C4 (mult(pwl 1 4000 1) (osc modstep) ) ) 

(stretch-abs 10
   (mytone)  )

The Nyquist prompt indicates: error: illegal character - -62
1> error: illegal character - -96
2> NIL
2> error: unexpected EOF
Function: #<Subr-(null): #78ff490>
Arguments:
#<File-Stream: #776e698>
#(
3> 2> 1>
It seems to me that there is a problem at the level of the modstep variable. What is strange, it is the value given to the modstep variable. Is this value badly noted?

(setq modstep (eql

Where does that “eql” come from? What is that supposed to do? Did you look up “eql” in the XLISP manual to see what it means?

Hello Sir.
I looked for a function in LISP who would look like in: two things are identical (in fact, they are not identical). I found only (eql [" (eql expr1 expr2) [LISP] - are the expressions identical? (works with all numbers)]. When I pass of a code written in Sal, in a code written in LISP, I try to stay near the initial code. I wanted to USE this code:

(abs-env
 (scale 0.5
  (mult (fmosc (hz-to-step 261.62) (pwl 1 4000 1)))))

Then add the modstep variable.

That’s right.
You have the wrong meaning of “=”.

In the SAL script it is “assigning”, as in: Let a = x + y
In your LISP code “eql” is testing equivalence, as in: If x = y

;; set modstep = hz-to-step((3.0 / 5.0) * step-to-hz(c4))
(setf modstep
  (hz-to-step (* (/ 3.0 5.0)
                 (step-to-hz C4))))

;; play fmosc(c4, pwl(1, 4000, 1) * osc(modstep)) ~ 10
(stretch-abs 10
  (fmosc C5 (mult (pwl 1 4000 1)
                  (osc modstep))))

I thank you.
I do not understant how this code works. If the sign = means: something is equal to the sum of x more y, It would mean that “modstep” here is equal to the sum of x more y.
It is just if I say that x is equal in:(hz-to-step
and y is equal in: (* (3.0 5.0) (step-to-hz C4)) or (* (0.6 step-to-hz C4))
0.6 is a step number (like 60 for C4 ?)
C4 = 261.62 Hz
Did I understand well?

(setf modstep
  (hz-to-step (* (/ 3.0 5.0)
                 (step-to-hz C4))))

This means:
Set the value of modstep to a specified value.
The value that is specified is: _(hz-to-step ( (/ 3.0 5.0) (step-to-hz C4)))_*

The above code is written in LISP syntax.
In SAL syntax it would be written as:

set modstep = hz-to-step((3.0 / 5.0) * step-to-hz(c4))

I think that you are making learning Nyquist hard for yourself. You do not yet know how to program in SAL or in LISP syntax, and I can see that it is difficult to translate from SAL to LISP when you don’t know either of them. I would suggest that you stop trying to translate from SAL to LISP, and spend time with LISP so that you can start to learn the LISP syntax. You will probably not need to learn SAL if you learn LISP.