
  '$ FileName "SynthDem19.exe"
  'uses rtl32

  #define stereo

  uses minwin
  uses waves.h
  uses waves.inc
  '
  '
  WaveOut w        'wave channel (includes stereo)

  double  v        'general
  double  ltime    'lapsed time in seconds

  single,
          vol,      'main channel vol
          a,        'wave pulse
          reverba,  'reverberation amplitude 0..1
          nreverba  'non reverb amplitude    0..1

  sys,
          i,       'iterator
          p,       'buffer output position (time bytes) not position in loop
          q,       'buffer input position (time bytes) not positition in loop
          frag,    'size of sound segment (bytes)
          seg,     'size of soung segment (samples)
          reverbt, 'reverberation delay time in bytes 'usually 1/44100 secs *2 *nchannels
          halt     'flag to stop playing and close the wave channel
  '
  '================
  'INITIAL SETTINGS
  '================
  '
  'REVERB SETTINGS

  reverba=0.25
  nreverba=0.75
  reverbt=0.25*88200*wfx.nchannels 'max buffersize 64k per channel
  '
  'GENERAL SETTINGS
  '
  seg=1000 'samples @44100 per second
  frag=seg*2*wfx.nchannels
  vol=1
  '

  '==========
  Class Sound
  '==========
  '
  'WAVE PULSE
  '
  single a,pa,amp
  '
  'FILTER
  '
  single filt,filtpr,filtba,lp,hp
  '
  'MAIN WAVE
  '
  single freq,phase,phdis,nfreq,ifreq,basefreq,startfreq
  '
  'HARMONICS
  '
  single freq1,phase1,phdis1
  single freq2,phase2,phdis2
  single freq3,phase3,phdis3
  single phase,phdis,vphase,pphase,pw
  '
  'OTHER
  '
  single du,v

  '
  'ENVELOPE / TIME MEASUREMENT
  '
  sys b,c,d1,d2,d3,dc,du1,du2
  sys decay
  '
  'WAVE CYCLE COUNTERS
  '
  sys pc,opc
  '
  'PITCH / NOTES
  '
  sys FirstScale,LastScale
  sys scaleNo,scaleLen,downScale,sfi
  sys n,rn,pn,ch
  '

  
  method initA() as sys
  '====================
  '
  'GENERAL SETTINGS
  '
  du1=33.33*441 '441=1/100 second
  du2=10 'nominal scale notes
  FirstScale=17
  LastScale=FirstScale
  scaleNo=FirstScale
  amp=0
  basefreq=110 'A
  filtba=1
  '
  startfreq=basefreq
  nfreq=basefreq
  freq=basefreq
  '
  end method 'initA



  method processA() as single
  '==========================
  single a
  '
  'FUNDAMENTAL PHASE
  '
  v=freq*ltime+phdis
  phase=frac(v)
  pc=v-phase 'wave counter
  '
  'HARMONIC PHASES
  '
  phase1=frac(freq1*ltime+phdis1)
  phase2=frac(freq2*ltime+phdis2)
  phase3=frac(freq3*ltime+phdis3)
  vphase=frac(6*ltime)
  '
  '
  'NEW WAVE OR PULSE
  '
  if pc<>opc then
    '
    opc=pc
    '
    'ENVELOPE  
    '
    if decay then
      amp*=.995
    else
      amp+=2000
      'amp=3000 'PLUCK
    end if
    if amp>=4000 then amp=4000 : decay=1
    'amp=3000
    '
    'AUX OSCILLATORS
    '===============
    '
    pphase=frac(.25*ltime)
    '
    'SLIDE NOTES
    '===========
    '
    'ensure no overshoot
    '
    if basefreq=nfreq then
      'ALREADY AT FINAL PITCH
    elseif abs(nfreq-basefreq)<abs(ifreq) then
      nfreq=basefreq 'LOCK INTO FINAL PITCH
    else 
      nfreq+=ifreq 'STEP TOWARDS TARGET NOTE PITCH
    end if
    '
    freq=nfreq
    '
    'VIBRATO (frequency modulation)
    '==============================
    '
    'v=sqrd(vphase)
    'freq+=du*v*basefreq*.01 'NOTE TIME-DEPENDENT VIBRATO
    '
    'SYNC PHASE FOR WAVE CONTINUITY
    '==============================
    '
    phdis=phase-freq*ltime
    '
    'HARMONIC PHASE SYNC
    '===================
    '
    freq1=freq*1.333 : phdis1=phase1-freq1*ltime
    freq2=freq*1.5   : phdis2=phase2-freq2*ltime
    freq3=freq*2.0   : phdis3=phase3-freq3*ltime
    '
  end if
  '
  'WAVE FORMS
  '==========
  '
  'a+=amp*noiseInterp(pc,phase)
  'a+=amp*noise(phase*30)
  'a+=amp*sawtooth(phase)*.25
  a+=amp*triangle(phase) '*noiseInterp(pc,phase)
  'a+=amp*sin(pi2*phase)  'sine wave  fundamental
  'a+=amp*sin(pi2*phase3)  'sine wave  harmonic
  'a+=amp*square(phase)*.25*(1-du)
  'a+=amp*sqrd(phase)*du

  'PULSE WIDTH MODULATION
  '======================
  '
  'pw=(1+sin(pi2*pphase))*.20
  'pw=(1+triangle(pphase))*.23
  'pw=.49-(1+sawtooth(pphase))*.245
  'pw=.45*du*du
  'pw=.45-.45*du
  '
  '-FOR STRINGS
  '
  'pw=(1+sawtooth(pphase))*.245
  'pw=.45*amp/4000
  'pw=.45-.45*amp/4000
  '
  'a+=amp*pulsewidth(phase,pw) 'ph: max 0 to min <.5
  'a+=amp*pulsewidth(phase,.45-pw) 'ph: max 0 to min <.5
  '
  'SYNC PULSEWIDTH TO NOTE DURATION (EXCEPT SLIDE TIME)
  '
  if basefreq=nfreq
    du=du1-dc
    if du>=1 then
      du=(d1-dc)/du
    else
      du=0
    end if
  else
    dc=d1 : du=0
  end if
  '
  'if du>1 then du=1
  '
  'du=d1/20 '(INCLUDING SLIDE TIME)
  '
  'a+=amp*pulsewidth(phase,.45*du) 'ph: max 0 to min <.5
  '
  'FILTER
  '
  filtpr=.3 ' .1==4400 HZ 
  filt=filt*(1-filtpr)+a*filtpr 'ACCUMULATE
  lp=filt       'low pass
  hp=a-filt
  'hp=a-pa
  pa=a
  '
  'a=lp*filtba + hp*(1-filtba) 'moving filter mix
  'a=lp
  'a=hp*5
  '
  'SYNC FILTER TO NOTE DURATION
  '
  'a=lp*(1-du)*1+hp*du*3
  'a=hp*(1-du)*2+lp*du*2
  '
  'TREMOLO (amplitude modulation)
  '
  'a=a*(0+(1+sqrd(vphase)))*.5
  'a=a*(0+(1+triangle(vphase)))*.5
  'a=a*(0+(1+square(vphase)))*.9
  'a=a*(0+(1+sin(pi2*vphase)))*.5
  '
  'CHANGE NOTE
  '
  if ++d1=du1 then
    d1=0
    d2++
    '
    'INCR PITCH
    '
    'basefreq*=1.0375
    '
    'USE SELECTED SCALES
    '
    '
    sys ch
    scaleLen=len scale(ScaleNo)
    '
    'CHOOSE A NOTE FROM FORWARD OR REVERSE SEQUENCE
    '
    if downScale then
      n=ScaleLen-d2+1
      if n=1 then d2++
    else
      n=d2
    end if
    '
    'CHOOSE A RANDOM DIFFERENT NOTE
    '
    'while rn=pn
    '  rn=rand(1,scaleLen)
    'wend
    'pn=rn
    '
    'n=rn
    '
    'DECODE PITCH CHARS INTO FREQUENCY
    '
    ch=asc(scale(scaleNo),n)
    select ch
    case 49 to 57 : ch-=49
    case 48       : ch=9
    case 45       : ch=10
    case 61       : ch=11
    case 0
      ch=12 'octave
    end select
    ch+=3 'shift to middle C
    '
    '
    nfreq=basefreq
    basefreq=pow(2,ch/12)*startfreq  'NEW PITCH
    ifreq=(basefreq-nfreq)*.025   'PITCH SLIDING
    '
    'basefreq=startfreq   'FIXED PITCH

    nfreq=basefreq 'NO PITCH SLIDE
    '
    decay=0
    '
    'MASTER FADE OUT
    '
    if basefreq>1000 then vol*=.9
    '
    'EXIT
    '
    if basefreq>22050 then vol=0
    '
    'END OF SCALE
    '============
    '
    if d2>ScaleLen then
      d2=0
      downscale++
      '
      if downscale=2 then
        downscale=0
        '
        'SCALE BASE CHANGE
        '
        if ++scaleNo>LastScale then
          scaleNo=FirstScale 'START AGAIN WITH FIRST SCALE
          sfi+=2 'INCREASE BY SEMITONES
          startfreq=110*pow(2,sfi/12)
        end if
      end if
      '
      'filtba-=.1
      'if filtba<=0 then exit method
      '
    end if
  end if
  '
  return a
  end method

  end class







  sound soundA, soundB
  soundA.initA
  soundB.initA
  SoundB.FirstScale=18
  SoundB.LastScale=18
  SoundB.ScaleNo=18
  '
  w.WavoStart 
  '
  '
  '
  '=================
  'MAIN PROCESS LOOP
  '=================
  '
  q=frag
  do
  '
  p=w.wavopos 'position in bytes used as a measure of time (diregarding loop)

  if GetAsyncKeyState (27) and 0xffff then halt=1
  '
  if halt then
    vol*=.98 'QUICK FADE
  end if
  '
  if vol<.001 then exit do
  '
  if p+frag<q then 'ahead ~ 1/44 sec when seg=1000
    sleep 5
    continue do
  end if
  '
  '=====================
  'PROCESS NOTE FRAGMENT
  '=====================
  '
  for i=1 to seg
  '
  'PHASE AND WAVE COUNTER
  '
  ltime=q*ipuls
  '
  'a=vol*SoundA.processA()
  a=vol*(.5*SoundA.processA()+.5*SoundB.processA())

  SendToBuffer 'macro
  #ifdef stereo
  SendToBuffer 'macro
  #endif
  a=0
  '
  next
  '
  sleep 5
  '
  enddo 'MAIN PROCESSING LOOP
  '
  w.WavoEnd
   
