1
2// vowels.saol
3// A simple singing synthesizer
4// Originally written by Eric Scheirer
5// Modified by John Lazzaro
6// Song length: 10 seconds
7//
8// Changes:
9//
10//    [1] "Fast" option uses table to replace buzz()
11//    [2] Variable tcount counts number of kcycles for a
12//        vowel transition -- previous implementation was prone
13//        to roundoff.
14//    [3] K-rate cpsmidi() opcode was part of a-rate statement in
15//        original, a strict decoder would not produce desired sound.
16//
17// This instrument should work as is in pre-FDIS saolc.
18
19global {
20  srate 44100 ;
21  krate 420 ;
22  outchannels 1 ;
23  }
24
25instr voice1 ( startmidi , startvwl , startamp ) {
26  asig vibfreq , a , reson1 , reson2 , out ;
27  ksig kinit , f1 , f2 , curf1 , curf2 , ct , oldf1 , oldf2, tcount ;
28  imports ksig vowel,  amp , pitch , cpspitch, stop ;
29  table vib ( harm , 128 , 1 ) ;
30  table buzztable(buzz, 128, 0, 1, 0.8);
31  ivar trans, ratio, fast ;
32
33  // i-rate
34
35  fast = 0;       // 1 chooses table implementation
36  trans = 0.100 ; // transition time between vowels, in seconds
37  ratio = 40;     // number of kcycles for a transition (16000/400)
38
39  // k-rate
40
41  if ( ! kinit ) {      // initializes pitch/loudness/format at note launch
42    kinit = 1 ;
43    vowel = startvwl ;
44    amp = startamp ;
45    pitch = startmidi ;
46    }
47  if ( stop ) {
48    turnoff ;
49    }
50  cpspitch = cpsmidi ( pitch );
51
52  // calculate end-points of vowel formats
53
54  if ( vowel == 1 ) {    // /i/
55    f1 = 260 ;
56    f2 = 2200 ;
57    }
58  if ( vowel == 2 ) {    // /u/
59    f1 = 310 ;
60    f2 = 900 ;
61    }
62  if ( vowel == 3 ) {    // /a/
63    f1 = 750 ;
64    f2 = 1100 ;
65    }
66  if ( vowel == 4 ) {    // /E/
67    f1 = 550 ;
68    f2 = 1750 ;
69    }
70  if ( ! oldf1 ) {      // initialization for note startup
71    tcount = ratio;
72    oldf1 = f1 ;
73    curf1 = f1 ;
74    oldf2 = f2 ;
75    curf2 = f2 ;
76    }
77  if ( f1 != oldf1 || f2 != oldf2 ) {  // computes smooth format shift
78    curf1 = oldf1 + ct / trans * ( f1 - oldf1 ) ;
79    curf2 = oldf2 + ct / trans * ( f2 - oldf2 ) ;
80    ct = ct + 1 / k_rate ;
81    tcount = tcount - 1;
82    }
83  if ( tcount == 0 ) {  // terminus of format shift
84    ct = 0 ;
85    oldf1 = f1 ;
86    oldf2 = f2 ;
87    tcount = ratio;
88    }
89
90  // a-rate
91
92  // vibrato'd singing frequency
93  vibfreq = cpspitch * ( oscil ( vib , 5 , - 1 ) * 0.020000 + 1 ) / 2 + arand ( 5 ) ;
94
95  if (!fast)  // computes raw glottal waveform
96   {
97     a = amp * buzz ( vibfreq , 0 , 1 , 0.800000 ) ;
98   }
99  else
100   {
101     a = amp * oscil ( buzztable, vibfreq ) ;
102   }
103
104  // apply resonances
105  // note bandpass is non-normative, will sound different with
106  // different decoders
107
108  reson1 = bandpass ( a , curf1 , curf1 / 5.500000 ) ;
109  reson2 = bandpass ( a , curf2 , curf2 / 5.500000 ) ;
110
111  // blended final output
112
113  out = ( a / 4 + reson1 + reson2 ) / 2 ;
114  output ( out ) ;
115
116  }
117
118