Friday, July 21, 2017

ex3A05. Audio Vector

# ex3A05.py
# Audio vector

from moduleCsound import *

tags(1)

header(ksmps=5)

add(r"""
instr 1
aSine      oscils     1, 2205, 0
kVec1      vaget      0, aSine
kVec2      vaget      1, aSine
kVec3      vaget      2, aSine
kVec4      vaget      3, aSine
kVec5      vaget      4, aSine
           printks    "kVec1 = %f, kVec2 = %f, kVec3 = %f, kVec4 = %f, kVec5 = %f\n",\
                      0, kVec1, kVec2, kVec3, kVec4, kVec5
endin
""")

tags(2)

add("i 1 0 [1/2205]")

tags(3)

writeRun(__file__)

ex3A04. Performance pass no increment

# ex3A04.py
# Performance pass no increment

from moduleCsound import *

tags(1)

header(ksmps=4410)

add("""
instr 1
kcount    =         0; sets kcount to 0 at each k-cycle
kcount    =         kcount + 1; does not really increase ...
          printk    0, kcount; print the value
endin
""")

tags(2)

add("i 1 0 1")

tags(3)

writeRun(__file__)

ex3A03. Performance pass increment listen

# ex3A03.py
# Performance pass increment listen

from moduleCsound import *

tags(1)

header(ksmps=441)

add("""
;build a table containing a sine wave
giSine     ftgen      0, 0, 2^10, 10, 1
""")

add("""
instr Rise
kFreq      init       100
aSine      poscil     .2, kFreq, giSine
           outs       aSine, aSine
;increment frequency by 10 Hz for each k-cycle
kFreq      =          kFreq + 10
;print out the frequency for the last k-cycle
kLast      release
 if kLast == 1 then
           printk     0, kFreq
 endif
endin

instr Partials
;initialize kCount
kCount     init       100
;get new frequency if kCount equals 100, 200, ...
 if kCount % 100 == 0 then
kFreq      =          kCount
 endif
aSine      poscil     .2, kFreq, giSine
           outs       aSine, aSine
;increment kCount
kCount     =          kCount + 1
;print out kFreq whenever it has changed
           printk2    kFreq
endin
""")

tags(2)

add("""
i "Rise" 0 3
i "Partials" 4 31
""")

tags(3)

writeRun(__file__)

Output (Spectrograph view):


ex3A02. Performance pass increment

# ex3A02.py
# Performance pass increment

from moduleCsound import *

tags(1)

# Each k-time is 0.1 sec

header(ksmps=4410)

add("""
instr 1
kCount    init      0; set kcount to 0 first
kCount    =         kCount + 1; increase at each k-pass
          printk    0, kCount; print the value
endin
""")

tags(2)

# There are 10 k-passes in 1 sec

add("i 1 0 1")

tags(3)

writeRun(__file__)

ex3A01. Initialization pass

# ex3A01.py
# Initialization pass

from moduleCsound import *

tags(1)

header(ksmps=32)

# global

add("giGlobal   =          1/2")

# instruments

add("""
instr 1
iLocal     =          1/4
           print      giGlobal, iLocal
endin

instr 2
iLocal     =          1/5
           print      giGlobal, iLocal
endin
""")

tags(2)

# Only Initialization of instr 1 and instr 2

add("""
i 1 0 0
i 2 0 0
""")

tags(3)

writeRun(__file__)

Thursday, July 13, 2017

ex2E02. Record Realtime

# ex2E02.py
# Record RealTime

from moduleCsound import *

add(startSyn)

add(startOpt)
add("-odac")
add(stopOpt)

add(startIns)

header(ksmps=32)

add("seed      0 ;each time different seed for random")

add("""
  instr 1
kFreq     randomi   400, 800, 1 ;random sliding frequency
aSig      poscil    .2, kFreq ;sine with this frequency
kPan      randomi   0, 1, 1 ;random panning
aL, aR    pan2      aSig, kPan ;stereo output signal
          outs      aL, aR ;live output
          fout      "live_record.wav", 18, aL, aR ;write to soundfile
  endin
""")

tags(2)

add("i 1 0 10")
tags(3)

writeRun(__file__)

ex2E01. Render

Because we give a filename from the command prompt, it will take greater precedence than the one in CsOptions.


# ex2E01.py
# Render

from moduleCsound import *

add(startSyn)

add(startOpt)
add("-o Render.wav")
add(stopOpt)

add(startIns)

header(ksmps=32, nch=1)

add("""
instr 1
aSin      poscil    0dbfs/4, 440
          out       aSin
endin
""")

tags(2)

add("i 1 0 1")
tags(3)

writeRun(__file__)

ex2D02. Live Input

# ex2D02.py
# Live Input

from moduleCsound import *

add(startSyn)

add(startOpt)
add("-iadc -odac -B512 -b128")
add(stopOpt)

add(startIns)

header(ksmps=32)

add("""
instr 1
aIn       inch      1   ;take input from channel 1
kInLev    downsamp  aIn ;convert audio input to control signal
          printk    .2, abs(kInLev)
;make modulator frequency oscillate 200 to 1000 Hz
kModFreq  poscil    400, 1/2
kModFreq  =         kModFreq+600
aMod      poscil    1, kModFreq ;modulator signal
aRM       =         aIn * aMod ;ring modulation
          outch     1, aRM, 2, aRM ;output to channel 1 and 2
endin
""")

tags(2)

add("i 1 0 3600")
tags(3)

writeRun(__file__, False)

ex2D01. Get Device List

# ex2D01.py
# Get Device List

from moduleCsound import *

add(startSyn)

add(startOpt)
add("-iadc999 -odac999")
add(stopOpt)

add(startIns)

header(ksmps=32)

add("""
instr 1
endin
""")

tags(2)

tags(3)

writeRun(__file__, False)

ex2C03. Midi All In

# ex2C03.py
# Midi All In

from moduleCsound import *

add(startSyn)

add(startOpt)
add("-+rtmidi=virtual -Ma -odac")
add(stopOpt)

add(startIns)

header(ksmps=32)

add("""
instr 1
kStatus, kChan, kData1, kData2 midiin

if kStatus != 0 then ;print if any new MIDI message has been received
    printk 0, kStatus
    printk 0, kChan
    printk 0, kData1
    printk 0, kData2
endif

endin
""")

tags(2)

add("i1 0 3600")

tags(3)

writeRun(__file__, False)

ex2C02. Midi Controller In

# ex2C02.py
# Midi Controller In

from moduleCsound import *

add(startSyn)

add(startOpt)
add("-+rtmidi=virtual -M1 -odac")
add(stopOpt)

add(startIns)

header(ksmps=32)

add("""
instr 1
; --- receive controller number 1 on channel 1 and scale from 220 to 440
kFreq ctrl7  1, 1, 220, 440
; --- use this value as varying frequency for a sine wave
aOut  poscil 0.2, kFreq
      outs   aOut, aOut
endin
""")

tags(2)

add("i 1 0 60")

tags(3)

writeRun(__file__, False)

ex2C01. Midi Keyboard In

A MIDI Keyboard can be read acting as score for instrument 1. Note I have changed writeRun to change run parameter to False. This will only create csound .csd file.


# ex2C01.py
# Midi Keyboard In

from moduleCsound import *

add(startSyn)

add(startOpt)
add("-+rtmidi=portmidi -Ma -odac")
add(stopOpt)

add(startIns)

header(ksmps=32)

add("massign   0, 1 ;assign all MIDI channels to instrument 1")

add("""
instr 1
iCps    cpsmidi   ;get the frequency from the key pressed
iAmp    ampmidi   0dbfs * 0.3 ;get the amplitude
aOut    poscil    iAmp, iCps ;generate a sine tone
        outs      aOut, aOut ;write it to the output
endin
""")

tags(2)

tags(3)

writeRun(__file__, False)

ex2B01. Document Structure

# ex2B01.py
# Document Structure

from moduleCsound import *

tags(1)

header(ksmps=32, nch=1)

# --- instrument (440 Hz sig of 1 sec dur at 0.25 amp)

add("""
instr 1 ; a 440 Hz Sine Wave
aSin      poscil    0dbfs/4, 440
          out       aSin
endin
""")

tags(2)

add("i 1 0 1")

tags(3)

writeRun(__file__)

Output: (spectrograph view with setting of 8192 points, Blackmann-Harris window, and showing frequencies from 0 to 1000.



The reason for the lines at end is because it can not determine frequency there.

Tuesday, July 11, 2017

ex2A02. Hello Cabbage

This example requires the csound frontend called Cabbage be installed.


# ex2A02.py
# Hello Cabbage

from moduleCsound import *

add("""
<Cabbage>
form size(420,100)
keyboard bounds(10,10,300,80)
rslider bounds(325,15,80,80), channel("level"), text("Level"), range(0,1,0.3)
</Cabbage>
""")

tags(1)

header(ksmps=32)

# --- instrument

add("""
instr    1
 icps cpsmidi
 klev chnget  "level"
 a1   poscil klev*0.2,icps
      outs   a1,a1
endin
""")

add(stopIns, stopSyn)

writeRun(__file__)

ex2A01. Hello World

# ex2A01.py
# Hello World

from moduleCsound import *

tags(1)

header(ksmps=32, nch=1)

# --- instrument

add("""
instr 1
aSin      poscil    0dbfs/4, 440
          out       aSin
endin
""")

tags(2)

# --- score

add("i 1 0 1")

tags(3)

writeRun(__file__)

ex1D13. Simple Algorithmic Note Generator

# ex1D13.py
# Simple Algorithmic Note Generator

from moduleCsound import *

tags(1)

header(ksmps=32, nch=1)

# --- global
# GEN 17 - x,y pairs (-17 not normalized)
# Both tables of size 100 (- since not power of 2)

add("""
giNotes ftgen 0,0,-100,-17,0,48, 15,53, 30,55, 40,60, 50,63, 60,65, 79,67, 85,70, 90,72, 96,75
giDurs ftgen 0,0,-100,-17,0,2, 30,0.5, 75,1, 90,1.5
""")

# --- instruments
# instr 1 triggers instr 2

add("""
  instr 1
kDur  init        0.5             ; initial rhythmic duration
kTrig metro       2/kDur          ; metronome freq. 2 times inverse of duration
kNdx  trandom     kTrig,0,1       ; create a random index upon each metro 'click'
kDur  table       kNdx,giDurs,1   ; read a note duration value
      schedkwhen  kTrig,0,0,2,0,1 ; trigger a note!
  endin

  instr 2
iNote table     rnd(1),giNotes,1                 ; read a random value from the function table
aEnv  linsegr 0, 0.005, 1, p3-0.105, 1, 0.1, 0 ; amplitude envelope
iPlk  random 0.1, 0.3                         ; point at which to pluck the string
iDtn  random    -0.05, 0.05                      ; random detune
aSig  wgpluck2  0.98, 0.2, cpsmidinn(iNote+iDtn), iPlk, 0.06
      out       aSig * aEnv
  endin
""")

tags(2)

# --- score

add("""
i 1 0    300  ; start 3 long notes close after one another
i 1 0.01 300
i 1 0.02 300
""")

tags(3)

writeRun(__file__)

ex12D_1. Humanising (Without reseting clock)

We can remove the b statement from the score by creating a new placeholder {} in the string for start time, thus format requires 2 values now.


# ex1D12_1.py
# Humanising (Without reseting clock)

from moduleCsound import *

tags(1)

header(ksmps=32)

# --- global

add("giWave  ftgen  0, 0, 2^10, 10, 1,0,1/4,0,1/16,0,1/64,0,1/256,0,1/1024")

# --- instruments

add("""
  instr 1 ; an instrument with no 'humanising'
inote =       p4
aEnv  linen   0.1,0.01,p3,0.01
aSig  poscil  aEnv,cpsmidinn(inote),giWave
      outs    aSig,aSig
  endin

  instr 2 ; an instrument with 'humanising'
inote   =       p4

; generate some i-time 'static' random paramters
iRndAmp random -3,3   ; amp. will be offset by a random number of decibels
iRndNte random  -5,5   ; note will be offset by a random number of cents

; generate some k-rate random functions
kAmpWob rspline -1,1,1,10   ; amplitude 'wobble' (in decibels)
kNteWob rspline -5,5,0.3,10 ; note 'wobble' (in cents)

; calculate final note function (in CPS)
kcps    =        cpsmidinn(inote+(iRndNte*0.01)+(kNteWob*0.01))

; amplitude envelope (randomisation of attack time)
aEnv    linen   0.1*ampdb(iRndAmp+kAmpWob),0.01+rnd(0.03),p3,0.01
aSig    poscil  aEnv,kcps,giWave
        outs    aSig,aSig
endin
""")

tags(2)

scr = """
i {} {} 1   60
i .  + 2.5 69
i .  + 0.5 67
i .  + 0.5 65
i .  + 0.5 64
i .  + 3   62
i .  + 1   62
i .  + 2.5 70
i .  + 0.5 69
i .  + 0.5 67
i .  + 0.5 65
i .  + 3   64
"""

add("t 0 80")
add(scr.format(1, 0))
add(scr.format(2, 17))

tags(3)

writeRun(__file__)

ex1D12. Humanising

Here instrument 1 and instrument 2 is run with same frequencies. But with instrument 2, we add random values for envelope parameters. Rather than using csound macros I use a python string, with placeholder {}. There is also a tempo string and a reset clock; this due to fact that we use same times for second. Of course we could just have added {} for the start time, and added a format variable.


Python is a much better language at string manipulation than csound. It is better to use Python to write scores and only use csound opcodes for instruments. Also Python is much easier to debug.


# ex1D12.py
# Humanising

from moduleCsound import *

tags(1)

header(ksmps=32)

# --- global

add("giWave  ftgen  0, 0, 2^10, 10, 1,0,1/4,0,1/16,0,1/64,0,1/256,0,1/1024")

# --- instruments

add("""
  instr 1 ; an instrument with no 'humanising'
inote =       p4
aEnv  linen   0.1,0.01,p3,0.01
aSig  poscil  aEnv,cpsmidinn(inote),giWave
      outs    aSig,aSig
  endin

  instr 2 ; an instrument with 'humanising'
inote   =       p4

; generate some i-time 'static' random paramters
iRndAmp random -3,3   ; amp. will be offset by a random number of decibels
iRndNte random  -5,5   ; note will be offset by a random number of cents

; generate some k-rate random functions
kAmpWob rspline -1,1,1,10   ; amplitude 'wobble' (in decibels)
kNteWob rspline -5,5,0.3,10 ; note 'wobble' (in cents)

; calculate final note function (in CPS)
kcps    =        cpsmidinn(inote+(iRndNte*0.01)+(kNteWob*0.01))

; amplitude envelope (randomisation of attack time)
aEnv    linen   0.1*ampdb(iRndAmp+kAmpWob),0.01+rnd(0.03),p3,0.01
aSig    poscil  aEnv,kcps,giWave
        outs    aSig,aSig
endin
""")

tags(2)

scr = """
i {} 0 1   60
i .  + 2.5 69
i .  + 0.5 67
i .  + 0.5 65
i .  + 0.5 64
i .  + 3   62
i .  + 1   62
i .  + 2.5 70
i .  + 0.5 69
i .  + 0.5 67
i .  + 0.5 65
i .  + 3   64
"""

add("t 0 80")
add(scr.format(1))
add("b 17")
add(scr.format(2))

tags(3)

writeRun(__file__)

ex1D11. Random Walk2

# ex1D11.py
# Random Walk2

from moduleCsound import *

tags(1)

header(ksmps=128,nch=1)

# --- instruments

add("""
; random frequency
instr 1
kx  random  -p6, p6
kfreq  =  p5*2^kx
aout  oscil  p4, kfreq, 1
out  aout
endin

; random change of frequency
instr 2
kx  init  .5
kfreq  =  p5*2^kx
kv  random  -p6, p6
kv  =  kv*(1 - p7)
kx  =  kx + kv
aout  oscil  p4, kfreq, 1
out  aout
endin

; random change of change of frequency
instr 3
kv init 0
kx  init  .5
kfreq  =  p5*2^kx
ka  random  -p7, p7
kv  =  kv + ka
kv  =  kv*(1 - p8)
kx  =  kx + kv
kv  =  (kx < -p6 || kx > p6?-kv : kv)
aout  oscili  p4, kfreq, 1
out  aout

endin
""")

tags(2)

# --- score

add("""
f1 0 32768 10 1
; i1  p4  p5  p6
; i2  p4  p5  p6  p7
;  amp  c_fr  rand  damp
; i2 0 20  .1  600  0.01  0.001
;  amp  c_fr  d_fr  rand  damp
;  amp  c_fr  rand
; i1 0 20  .1  600  0.5
; i3  p4  p5  p6  p7  p8
i3 0 20  .1  600  1  0.001  0.001
""")

tags(3)

writeRun(__file__)

ex1D10. Rejection Sampling

# ex1D10.py
# Rejection Sampling

from moduleCsound import *

tags(1)

header(nch=1)

# --- user defined opcodes

add("""
; random number generator to a given density function
; kout random number; k_minimum,k_maximum,i_fn for a density function

opcode rand_density, k, kki
kmin,kmax,ifn xin
loop:
krnd1  random  0,1
krnd2  random  0,1
k2  table  krnd1,ifn,1
  if krnd2 > k2 kgoto loop
  xout  kmin+krnd1*(kmax-kmin)
endop

; random number generator to a given probability function
; kout random number
; in: i_nr number of possible values
; i_fn1 function for random values
; i_fn2 probability functionExponential: Generate a uniformly distributed number between 0 and 1 and take its natural logarithm.

opcode rand_probability, k, iii
inr,ifn1,ifn2 xin
loop:
krnd1  random  0,inr
krnd2  random  0,1
k2  table  int(krnd1),ifn2,0
  if krnd2 > k2 kgoto loop
kout  table  krnd1,ifn1,0
  xout  kout
endop
""")

# --- instruments

add("""
instr 1
krnd  rand_density 400,800,2
aout  poscil  .1,krnd,1
  out  aout
endin

instr 2
krnd  rand_probability p4,p5,p6
aout  poscil  .1,krnd,1
  out  aout
endin
""")

tags(2)

# --- tables

add("""
;sine
f1 0 32768 10 1
;density function
f2 0 1024 6 1 112 0 800 0 112 1
;random values and their relative probability (two dice)
f3 0 16 -2 2 3 4 5 6 7 8 9 10 11 12
f4 0 16  2 1 2 3 4 5 6 5 4  3  2  1
;random values and their relative probability
f5 0 8 -2 400 500 600 800
f6 0 8  2 .3  .8  .3  .1
""")

# --- score

add("""
i1 0 10
i2 0 10 4 5 6
""")

tags(3)

writeRun(__file__)

ex1D09. Random Walk

# ex1D09.py
# Random Walk

from moduleCsound import *

tags(1)

header(ksmps=32)

# --- globals

add(r"""
seed 1 ;change to zero for always changing results
;****SETTINGS FOR PITCHES****
 ;define the pitch street in octave notation
giLowestPitch =     7
giHighestPitch =    9
 ;set pitch startpoint, deviation range and the first direction
giStartPitch =      8
gkPitchDev init     0.2 ;random range for next pitch
gkPitchDir init     0.1 ;positive = upwards

;****SETTINGS FOR DENSITY****
 ;define the maximum and minimum density (notes per second)
giLowestDens =      1
giHighestDens =     8
 ;set first density
giStartDens =       3
 ;set possible deviation in range 0..1
 ;0 = no deviation at all
 ;1 = possible deviation is between half and twice the current density
gkDensDev init      0.5
 ;set direction in the same range 0..1
 ;(positive = more dense, shorter notes)
gkDensDir init      0.1
""")

# --- instruments

add(r"""
;****INSTRUMENT FOR RANDOM WALK****
  instr walk
 ;set initial values
kPitch    init      giStartPitch
kDens     init      giStartDens
 ;trigger impulses according to density
kTrig     metro     kDens
 ;if the metro ticks
 if kTrig == 1 then
  ;1) play current note
          event     "i", "play", 0, 1.5/kDens, kPitch
  ;2) calculate next pitch
   ;define boundaries according to direction
kLowPchBound =      gkPitchDir < 0 ? -gkPitchDev+gkPitchDir : -gkPitchDev
kHighPchBound =     gkPitchDir > 0 ? gkPitchDev+gkPitchDir : gkPitchDev
   ;get random value in these boundaries
kPchRnd   random    kLowPchBound, kHighPchBound
   ;add to current pitch
kPitch += kPchRnd
  ;change direction if maxima are crossed, and report
  if kPitch > giHighestPitch && gkPitchDir > 0 then
gkPitchDir =        -gkPitchDir
          printks   " Pitch touched maximum - now moving down.\n", 0
  elseif kPitch < giLowestPitch && gkPitchDir < 0 then
gkPitchDir =        -gkPitchDir
          printks   "Pitch touched minimum - now moving up.\n", 0
  endif
  ;3) calculate next density (= metro frequency)
   ;define boundaries according to direction
kLowDensBound =     gkDensDir < 0 ? -gkDensDev+gkDensDir : -gkDensDev
kHighDensBound =    gkDensDir > 0 ? gkDensDev+gkDensDir : gkDensDev
   ;get random value in these boundaries
kDensRnd  random    kLowDensBound, kHighDensBound
   ;get multiplier (so that kDensRnd=1 yields to 2, and kDens=-1 to 1/2)
kDensMult =         2 ^ kDensRnd
   ;multiply with current duration
kDens *= kDensMult
   ;avoid too high values and too low values
kDens     =         kDens > giHighestDens*1.5 ? giHighestDens*1.5 : kDens
kDens     =         kDens < giLowestDens/1.5 ? giLowestDens/1.5 : kDens
   ;change direction if maxima are crossed
  if (kDens > giHighestDens && gkDensDir > 0) || (kDens < giLowestDens && gkDensDir < 0) then
gkDensDir =         -gkDensDir
   if kDens > giHighestDens then
          printks   " Density touched upper border - now becoming less dense.\n", 0
          else
          printks   " Density touched lower border - now becoming more dense.\n", 0
   endif
  endif
 endif
  endin

;****INSTRUMENT TO PLAY ONE NOTE****
  instr play
 ;get note as octave and calculate frequency and panning
iOct       =          p4
iFreq      =          cpsoct(iOct)
iPan       ntrpol     0, 1, iOct, giLowestPitch, giHighestPitch
 ;calculate mode filter quality according to duration
iQ         ntrpol     10, 400, p3, .15, 1.5
 ;generate tone and throw out
aImp       mpulse     1, p3
aMode      mode       aImp, iFreq, iQ
aOut       linen      aMode, 0, p3, p3/4
aL, aR     pan2       aOut, iPan
           outs       aL, aR
  endin
""")

tags(2)

# --- score

add('i "walk" 0 999')

tags(3)

writeRun(__file__)

ex1D08. Markov Music

# ex1D08.py
# Markov Music

from moduleCsound import *

tags(1)

header(ksmps=32)

# --- globals
add("""
seed 0
;****DEFINITIONS FOR NOTES****
 ;notes as proportions and a base frequency
giNotes[]  array      1, 9/8, 6/5, 5/4, 4/3, 3/2, 5/3
giBasFreq  =          330
 ;probability of notes as markov matrix:
  ;first -> only to third and fourth
  ;second -> anywhere without self
  ;third -> strong probability for repetitions
  ;fourth -> idem
  ;fifth -> anywhere without third and fourth
  ;sixth -> mostly to seventh
  ;seventh -> mostly to sixth
giProbNotes[][] init  7, 7
giProbNotes array     0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0,
                      0.2, 0.0, 0.2, 0.2, 0.2, 0.1, 0.1,
                      0.1, 0.1, 0.5, 0.1, 0.1, 0.1, 0.0,
                      0.0, 0.1, 0.1, 0.5, 0.1, 0.1, 0.1,
                      0.2, 0.2, 0.0, 0.0, 0.2, 0.2, 0.2,
                      0.1, 0.1, 0.0, 0.0, 0.1, 0.1, 0.6,
                      0.1, 0.1, 0.0, 0.0, 0.1, 0.6, 0.1

;****DEFINITIONS FOR DURATIONS****
 ;possible durations
gkDurs[]    array     1, 1/2, 1/3
 ;probability of durations as markov matrix:
  ;first -> anything
  ;second -> mostly self
  ;third -> mostly second
gkProbDurs[][] init   3, 3
gkProbDurs array      1/3, 1/3, 1/3,
                      0.2, 0.6, 0.3,
                      0.1, 0.5, 0.4

;****SET FIRST NOTE AND DURATION FOR MARKOV PROCESS****
giPrevNote init       1
gkPrevDur  init       1
""")

# --- user defined opcodes

add("""
;****USER DEFINED OPCODES FOR MARKOV CHAINS****
  opcode Markov, i, i[][]i
iMarkovTable[][], iPrevEl xin
iRandom    random     0, 1
iNextEl    =          0
iAccum     =          iMarkovTable[iPrevEl][iNextEl]
 until iAccum >= iRandom do
iNextEl    +=         1
iAccum     +=         iMarkovTable[iPrevEl][iNextEl]
 enduntil
           xout       iNextEl
  endop

  opcode Markovk, k, k[][]k
kMarkovTable[][], kPrevEl xin
kRandom    random     0, 1
kNextEl    =          0
kAccum     =          kMarkovTable[kPrevEl][kNextEl]
 until kAccum >= kRandom do
kNextEl    +=         1
kAccum     +=         kMarkovTable[kPrevEl][kNextEl]
 enduntil
           xout       kNextEl
  endop
""")

# --- instruments

add(r"""
;****INSTRUMENT FOR DURATIONS****
  instr trigger_note
kTrig      metro      1/gkDurs[gkPrevDur]
 if kTrig == 1 then
           event      "i", "select_note", 0, 1
gkPrevDur  Markovk    gkProbDurs, gkPrevDur
 endif
  endin

;****INSTRUMENT FOR PITCHES****
  instr select_note
 ;choose next note according to markov matrix and previous note
 ;and write it to the global variable for (next) previous note
giPrevNote Markov     giProbNotes, giPrevNote
 ;call instr to play this note
           event_i    "i", "play_note", 0, 2, giPrevNote
 ;turn off this instrument
           turnoff
  endin

;****INSTRUMENT TO PERFORM ONE NOTE****
  instr play_note
 ;get note as index in ginotes array and calculate frequency
iNote      =          p4
iFreq      =          giBasFreq * giNotes[iNote]
 ;random choice for mode filter quality and panning
iQ         random     10, 200
iPan       random     0.1, .9
 ;generate tone and put out
aImp       mpulse     1, p3
aOut       mode       aImp, iFreq, iQ
aL, aR     pan2       aOut, iPan
           outs       aL, aR
  endin
""")

tags(2)

# --- score

add('i "trigger_note" 0 100')

tags(3)

writeRun(__file__)

ex1D07. Markov Basics

# ex1D07.py
# Markov Basics

from moduleCsound import *

tags(1)

header(ksmps=32)

# score written with python loop rather using r

# --- globals

add("seed 0")

# --- instrument

add(r"""
instr 1
iLine[]     array      .2, .5, .3
iVal        random     0, 1
iAccum      =          iLine[0]
iIndex      =          0
 until iAccum >= iVal do
iIndex      +=         1
iAccum      +=         iLine[iIndex]
 enduntil
            printf_i   "Random number = %.3f, next element = %c!\n", 1, iVal, iIndex+97
endin
""")

tags(2)

# --- score

for i in range(10):
    add("i 1 0 0")

tags(3)

writeRun(__file__)

ex1D06. Scalings

# ex1D06.py
# Scalings

from moduleCsound import *

tags(1)

header(ksmps=32)

# --- globals

add("""
;****POSSIBLE DURATIONS AS ARRAY****
giDurs[]   array      3/2, 1, 2/3, 1/2, 1/3, 1/4
giLenDurs  lenarray   giDurs

;****POSSIBLE PITCHES AS ARRAY****
 ;initialize array with 31 steps
giScale[]  init       31
giLenScale lenarray   giScale
 ;iterate to fill from 65 hz onwards
iStart     =          65
iDenom     =          3 ;start with 3/2
iCnt       =          0
 until iCnt = giLenScale do
giScale[iCnt] =       iStart
iStart     =          iStart * iDenom / (iDenom-1)
iDenom     +=         1 ;next proportion is 4/3 etc
iCnt       +=         1
 enduntil

;****SEQUENCE OF UNITS AS ARRAY****
giSequence[] array    0, 1.2, 1.4, 2.2, 2.4, 3.2, 3.6
giSeqIndx  =          0 ;startindex
""")

# --- user opcodes

add("""
;****UDO DEFINITIONS****
opcode linrnd_low, i, iii
 ;linear random with precedence of lower values
iMin, iMax, iMaxCount xin
 ;set counter and initial (absurd) result
iCount     =          0
iRnd       =          iMax
 ;loop and reset iRnd
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iRnd       =          iUniRnd < iRnd ? iUniRnd : iRnd
iCount += 1
enduntil
           xout       iRnd
endop

opcode linrnd_high, i, iii
 ;linear random with precedence of higher values
iMin, iMax, iMaxCount xin
 ;set counter and initial (absurd) result
iCount     =          0
iRnd       =          iMin
 ;loop and reset iRnd
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iRnd       =          iUniRnd > iRnd ? iUniRnd : iRnd
iCount += 1
enduntil
           xout       iRnd
endop

opcode trirnd, i, iii
iMin, iMax, iMaxCount xin
 ;set a counter and accumulator
iCount     =          0
iAccum     =          0
 ;perform loop and accumulate
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iAccum += iUniRnd
iCount += 1
enduntil
 ;get the mean and output
iRnd       =          iAccum / iMaxCount
           xout       iRnd
endop
""")

# --- INSTRUMENTS

add(r"""
;****ONE INSTRUMENT TO PERFORM ALL DISTRIBUTIONS****
;0 = uniform, 1 = linrnd_low, 2 = linrnd_high, 3 = trirnd
;the fractional part denotes the number of units, e.g.
;3.4 = triangular distribution with four sub-units

instr notes
 ;how many notes to be played
iHowMany   =          p4
 ;by which distribution with how many units
iWhich     =          giSequence[giSeqIndx]
iDistrib   =          int(iWhich)
iUnits     =          round(frac(iWhich) * 10)

 ;trigger as many instances of instr play as needed
iThisNote  =          0
iStart     =          0
iPrint     =          1

 ;for each note to be played
 until iThisNote == iHowMany do

  ;calculate iMidiPch and iDur depending on type
  if iDistrib == 0 then
           printf_i   "%s", iPrint, "... uniform distribution:\n"
           printf_i   "%s", iPrint, "EQUAL LIKELINESS OF ALL PITCHES AND DURATIONS\n"
iScaleIndx random     0, giLenScale-.0001 ;midi note
iDurIndx   random     0, giLenDurs-.0001 ;duration
  elseif iDistrib == 1 then
           printf_i   "... linear low distribution with %d units:\n", iPrint, iUnits
           printf_i   "%s", iPrint, "LOWER NOTES AND LONGER DURATIONS PREFERRED\n"
iScaleIndx linrnd_low 0, giLenScale-.0001, iUnits
iDurIndx   linrnd_low 0, giLenDurs-.0001, iUnits
  elseif iDistrib == 2 then
           printf_i   "... linear high distribution with %d units:\n", iPrint, iUnits
           printf_i   "%s", iPrint, "HIGHER NOTES AND SHORTER DURATIONS PREFERRED\n"
iScaleIndx linrnd_high 0, giLenScale-.0001, iUnits
iDurIndx   linrnd_high 0, giLenDurs-.0001, iUnits
           else
           printf_i   "... triangular distribution with %d units:\n", iPrint, iUnits
           printf_i   "%s", iPrint, "MEDIUM NOTES AND DURATIONS PREFERRED\n"
iScaleIndx trirnd     0, giLenScale-.0001, iUnits
iDurIndx   trirnd     0, giLenDurs-.0001, iUnits
  endif

 ;call subinstrument to play note
iDur       =          giDurs[int(iDurIndx)]
iPch       =          giScale[int(iScaleIndx)]
           event_i    "i", "play", iStart, iDur, iPch

 ;increase start time and counter
iStart     +=         iDur
iThisNote  +=         1
 ;avoid continuous printing
iPrint     =          0
enduntil

 ;reset the duration of this instr to make all events happen
p3         =          iStart + 2

 ;increase index for sequence
giSeqIndx += 1
 ;call instr again if sequence has not been ended
 if giSeqIndx < lenarray(giSequence) then
           event_i    "i", "notes", p3, 1, iHowMany
 ;or exit
           else
           event_i    "i", "exit", p3, 1
 endif
endin


;****INSTRUMENTS TO PLAY THE SOUNDS AND EXIT CSOUND****
instr play
 ;increase duration in random range
iDur       random     p3*2, p3*5
p3         =          iDur
 ;get frequency
iFreq      =          p4
 ;generate note with karplus-strong algorithm
aPluck     pluck      .2, iFreq, iFreq, 0, 1
aPluck     linen      aPluck, 0, p3, p3
 ;filter
aFilter    mode       aPluck, iFreq, .1
 ;mix aPluck and aFilter according to freq
 ;(high notes will be filtered more)
aMix       ntrpol     aPluck, aFilter, iFreq, 65, 65*16
 ;panning also according to freq
 ;(low = left, high = right)
iPan       =          (iFreq-65) / (65*16)
aL, aR     pan2       aMix, iPan
           outs       aL, aR
endin

instr exit
           exitnow
endin
""")

tags(2)

# --- score

add("""
i "notes" 0 1 23 ;set number of notes per instr here
e 99999 ;make possible to perform long (exit will be automatically)
""")

tags(3)

writeRun(__file__)

ex1D05. More Linear Triangular Units

# ex1D05.py
# More Linear Triangular Units

from moduleCsound import *

tags(1)

header(ksmps=32)

# --- globals

add("""
;****SEQUENCE OF UNITS AS ARRAY****/
giSequence[] array 0, 1.2, 1.4, 2.2, 2.4, 3.2, 3.6
giSeqIndx = 0 ;startindex
""")

# --- user opcodes

add("""
;****UDO DEFINITIONS****
opcode linrnd_low, i, iii
 ;linear random with precedence of lower values
iMin, iMax, iMaxCount xin
 ;set counter and initial (absurd) result
iCount     =          0
iRnd       =          iMax
 ;loop and reset iRnd
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iRnd       =          iUniRnd < iRnd ? iUniRnd : iRnd
iCount     +=         1
 enduntil
           xout       iRnd
endop

opcode linrnd_high, i, iii
 ;linear random with precedence of higher values
iMin, iMax, iMaxCount xin
 ;set counter and initial (absurd) result
iCount     =          0
iRnd       =          iMin
 ;loop and reset iRnd
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iRnd       =          iUniRnd > iRnd ? iUniRnd : iRnd
iCount     +=         1
 enduntil
           xout       iRnd
endop

opcode trirnd, i, iii
iMin, iMax, iMaxCount xin
 ;set a counter and accumulator
iCount     =          0
iAccum     =          0
 ;perform loop and accumulate
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iAccum     +=         iUniRnd
iCount     +=         1
 enduntil
 ;get the mean and output
iRnd       =          iAccum / iMaxCount
           xout       iRnd
endop
""")

# --- INSTRUMENTS

add(r"""
;****ONE INSTRUMENT TO PERFORM ALL DISTRIBUTIONS****
;0 = uniform, 1 = linrnd_low, 2 = linrnd_high, 3 = trirnd
;the fractional part denotes the number of units, e.g.
;3.4 = triangular distribution with four sub-units

instr notes
 ;how many notes to be played
iHowMany   =          p4
 ;by which distribution with how many units
iWhich     =          giSequence[giSeqIndx]
iDistrib   =          int(iWhich)
iUnits     =          round(frac(iWhich) * 10)
 ;set min and max duration
iMinDur    =          .1
iMaxDur    =          2
 ;set min and max pitch
iMinPch    =          36
iMaxPch    =          84

 ;trigger as many instances of instr play as needed
iThisNote  =          0
iStart     =          0
iPrint     =          1

 ;for each note to be played
 until iThisNote == iHowMany do

  ;calculate iMidiPch and iDur depending on type
  if iDistrib == 0 then
           printf_i   "%s", iPrint, "... uniform distribution:\n"
           printf_i   "%s", iPrint, "EQUAL LIKELIHOOD OF ALL PITCHES AND DURATIONS\n"
iMidiPch   random     iMinPch, iMaxPch ;midi note
iDur       random     iMinDur, iMaxDur ;duration
  elseif iDistrib == 1 then
           printf_i    "... linear low distribution with %d units:\n", iPrint, iUnits
           printf_i    "%s", iPrint, "LOWER NOTES AND LONGER DURATIONS PREFERRED\n"
iMidiPch   linrnd_low iMinPch, iMaxPch, iUnits
iDur       linrnd_high iMinDur, iMaxDur, iUnits
  elseif iDistrib == 2 then
           printf_i    "... linear high distribution with %d units:\n", iPrint, iUnits
           printf_i    "%s", iPrint, "HIGHER NOTES AND SHORTER DURATIONS PREFERRED\n"
iMidiPch   linrnd_high iMinPch, iMaxPch, iUnits
iDur       linrnd_low iMinDur, iMaxDur, iUnits
  else
           printf_i    "... triangular distribution with %d units:\n", iPrint, iUnits
           printf_i    "%s", iPrint, "MEDIUM NOTES AND DURATIONS PREFERRED\n"
iMidiPch   trirnd     iMinPch, iMaxPch, iUnits
iDur       trirnd     iMinDur, iMaxDur, iUnits
  endif

 ;call subinstrument to play note
           event_i    "i", "play", iStart, iDur, int(iMidiPch)

 ;increase start tim and counter
iStart     +=         iDur
iThisNote  +=         1
 ;avoid continuous printing
iPrint     =          0
 enduntil

 ;reset the duration of this instr to make all events happen
p3         =          iStart + 2

 ;increase index for sequence
giSeqIndx  +=         1
 ;call instr again if sequence has not been ended
 if giSeqIndx < lenarray(giSequence) then
           event_i    "i", "notes", p3, 1, iHowMany
 ;or exit
 else
           event_i    "i", "exit", p3, 1
 endif
endin


;****INSTRUMENTS TO PLAY THE SOUNDS AND EXIT CSOUND****
instr play
 ;increase duration in random range
iDur       random     p3, p3*1.5
p3         =          iDur
 ;get midi note and convert to frequency
iMidiNote  =          p4
iFreq      cpsmidinn  iMidiNote
 ;generate note with karplus-strong algorithm
aPluck     pluck      .2, iFreq, iFreq, 0, 1
aPluck     linen      aPluck, 0, p3, p3
 ;filter
aFilter    mode       aPluck, iFreq, .1
 ;mix aPluck and aFilter according to MidiNote
 ;(high notes will be filtered more)
aMix       ntrpol     aPluck, aFilter, iMidiNote, 36, 84
 ;panning also according to MidiNote
 ;(low = left, high = right)
iPan       =          (iMidiNote-36) / 48
aL, aR     pan2       aMix, iPan
           outs       aL, aR
endin

instr exit
           exitnow
endin
""")

tags(2)

# --- score

add("""
i "notes" 0 1 23 ;set number of notes per instr here
e 99999 ;make possible to perform long (exit will be automatically)
""")

tags(3)

writeRun(__file__)

ex1D04. Triangular Random

# ex1D04.py
# Triangular Random

from moduleCsound import *

tags(1)

header(ksmps=32)

# trirnd opcode defined for TRIANGULAR DISTRIBUTION
# only "notes_uniform" instrument called, within score, which calls others

add("""
;****UDO FOR TRIANGULAR DISTRIBUTION****
opcode trirnd, i, ii
iMin, iMax xin
 ;generate two random values with the random opcode
iOne       random     iMin, iMax
iTwo       random     iMin, iMax
 ;get the mean and output
iRnd       =          (iOne+iTwo) / 2
           xout       iRnd
endop
""")

add(r"""
;****INSTRUMENTS FOR UNIFORM AND TRIANGULAR DISTRIBUTION****

instr notes_uniform
           prints     "... instr notes_uniform playing:\n"
           prints     "EQUAL LIKELINESS OF ALL PITCHES AND DURATIONS\n"
 ;how many notes to be played
iHowMany   =          p4
 ;trigger as many instances of instr play as needed
iThisNote  =          0
iStart     =          0
 until iThisNote == iHowMany do
iMidiPch   random     36, 84 ;midi note
iDur       random     .25, 1.75 ;duration
           event_i    "i", "play", iStart, iDur, int(iMidiPch)
iStart     +=         iDur ;increase start
iThisNote  +=         1 ;increase counter
 enduntil
 ;reset the duration of this instr to make all events happen
p3         =          iStart + 2
 ;trigger next instrument two seconds after the last note
           event_i    "i", "notes_trirnd", p3, 1, iHowMany
endin

instr notes_trirnd
           prints     "... instr notes_trirnd playing:\n"
           prints     "MEDIUM NOTES AND DURATIONS PREFERRED\n"
iHowMany   =          p4
iThisNote  =          0
iStart     =          0
 until iThisNote == iHowMany do
iMidiPch   trirnd     36, 84 ;medium pitches preferred
iDur       trirnd     .25, 1.75 ;medium durations preferred
           event_i    "i", "play", iStart, iDur, int(iMidiPch)
iStart     +=         iDur
iThisNote  +=         1
 enduntil
 ;reset the duration of this instr to make all events happen
p3         =          iStart + 2
 ;call instr to exit csound
           event_i    "i", "exit", p3+1, 1
endin


;****INSTRUMENTS TO PLAY THE SOUNDS AND EXIT CSOUND****

instr play
 ;increase duration in random range
iDur       random     p3, p3*1.5
p3         =          iDur
 ;get midi note and convert to frequency
iMidiNote  =          p4
iFreq      cpsmidinn  iMidiNote
 ;generate note with karplus-strong algorithm
aPluck     pluck      .2, iFreq, iFreq, 0, 1
aPluck     linen      aPluck, 0, p3, p3
 ;filter
aFilter    mode       aPluck, iFreq, .1
 ;mix aPluck and aFilter according to MidiNote
 ;(high notes will be filtered more)
aMix       ntrpol     aPluck, aFilter, iMidiNote, 36, 84
 ;panning also according to MidiNote
 ;(low = left, high = right)
iPan       =          (iMidiNote-36) / 48
aL, aR     pan2       aMix, iPan
           outs       aL, aR
endin

instr exit
           exitnow
endin
""")

tags(2)

add("""
i "notes_uniform" 0 1 23 ;set number of notes per instr here
;instr trirnd will be triggered automatically
e 99999 ;make possible to perform long (exit will be automatically)
""")

tags(3)

writeRun(__file__)

ex1D03. Linear Random

# ex1D03.py
# Linear Random

from moduleCsound import *

tags(1)

header(ksmps=32)

# new opcodes defined for linrnd_low and linrnd_high
# The ouput is 1 i-time variable (xout)
# The input is 2 i-time variables (xin)

# score only calls "notes_uniform" instrument.
# It calls others, and finally "exit".
# pluck - karplus strong algorithm

add("""
;****DEFINE OPCODES FOR LINEAR DISTRIBUTION****

opcode linrnd_low, i, ii ; output (1 i value), input(2 i values)
 ;linear random with precedence of lower values
iMin, iMax xin
 ;generate two random values with the random opcode
iOne       random     iMin, iMax
iTwo       random     iMin, iMax
 ;compare and get the lower one
iRnd       =          iOne < iTwo ? iOne : iTwo
           xout       iRnd
endop

opcode linrnd_high, i, ii
 ;linear random with precedence of higher values
iMin, iMax xin
 ;generate two random values with the random opcode
iOne       random     iMin, iMax
iTwo       random     iMin, iMax
 ;compare and get the higher one
iRnd       =          iOne > iTwo ? iOne : iTwo
           xout       iRnd
endop
""")

add(r"""
;****INSTRUMENTS FOR THE DIFFERENT DISTRIBUTIONS****

instr notes_uniform
           prints     "... instr notes_uniform playing:\n"
           prints     "EQUAL LIKELINESS OF ALL PITCHES AND DURATIONS\n"
 ;how many notes to be played
iHowMany   =          p4
 ;trigger as many instances of instr play as needed
iThisNote  =          0
iStart     =          0
 until iThisNote == iHowMany do
iMidiPch   random     36, 84 ;midi note
iDur       random     .5, 1 ;duration
           event_i    "i", "play", iStart, iDur, int(iMidiPch)
iStart     +=         iDur ;increase start
iThisNote  +=         1 ;increase counter
 enduntil
 ;reset the duration of this instr to make all events happen
p3         =          iStart + 2
 ;trigger next instrument two seconds after the last note
           event_i    "i", "notes_linrnd_low", p3, 1, iHowMany
endin

instr notes_linrnd_low
           prints     "... instr notes_linrnd_low playing:\n"
           prints     "LOWER NOTES AND LONGER DURATIONS PREFERRED\n"
iHowMany   =          p4
iThisNote  =          0
iStart     =          0
 until iThisNote == iHowMany do
iMidiPch   linrnd_low 36, 84 ;lower pitches preferred
iDur       linrnd_high .5, 1 ;longer durations preferred
           event_i    "i", "play", iStart, iDur, int(iMidiPch)
iStart     +=         iDur
iThisNote  +=         1
 enduntil
 ;reset the duration of this instr to make all events happen
p3         =          iStart + 2
 ;trigger next instrument two seconds after the last note
           event_i    "i", "notes_linrnd_high", p3, 1, iHowMany
endin

instr notes_linrnd_high
           prints     "... instr notes_linrnd_high playing:\n"
           prints     "HIGHER NOTES AND SHORTER DURATIONS PREFERRED\n"
iHowMany   =          p4
iThisNote  =          0
iStart     =          0
 until iThisNote == iHowMany do
iMidiPch   linrnd_high 36, 84 ;higher pitches preferred
iDur       linrnd_low .3, 1.2 ;shorter durations preferred
           event_i    "i", "play", iStart, iDur, int(iMidiPch)
iStart     +=         iDur
iThisNote  +=         1
 enduntil
 ;reset the duration of this instr to make all events happen
p3         =          iStart + 2
 ;call instr to exit csound
           event_i    "i", "exit", p3+1, 1
endin


;****INSTRUMENTS TO PLAY THE SOUNDS AND TO EXIT CSOUND****

instr play
 ;increase duration in random range
iDur       random     p3, p3*1.5
p3         =          iDur
 ;get midi note and convert to frequency
iMidiNote  =          p4
iFreq      cpsmidinn  iMidiNote
 ;generate note with karplus-strong algorithm
aPluck     pluck      .2, iFreq, iFreq, 0, 1
aPluck     linen      aPluck, 0, p3, p3
 ;filter
aFilter    mode       aPluck, iFreq, .1
 ;mix aPluck and aFilter according to MidiNote
 ;(high notes will be filtered more)
aMix       ntrpol     aPluck, aFilter, iMidiNote, 36, 84
 ;panning also according to MidiNote
 ;(low = left, high = right)
iPan       =          (iMidiNote-36) / 48
aL, aR     pan2       aMix, iPan
           outs       aL, aR
endin

instr exit
           exitnow
endin
""")

tags(2)

add("""
i "notes_uniform" 0 1 23 ;set number of notes per instr here
;instruments linrnd_low and linrnd_high are triggered automatically
e 99999 ;make possible to perform long (exit will be automatically)
""")

tags(3)

writeRun(__file__)

ex3A05. Audio Vector