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