1 /*  SpiralSynth
2  *  Copyleft (C) 2000 David Griffiths <dave@pawfal.org>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 
19 #include "Oscillator.h"
20 #include "Output.h"
21 #include <stdlib.h>
22 #include <limits.h>
23 
24 static const short MAX_LEV = 10000;
25 
26 Oscillator::Oscillator() :
27 m_Type(SQUARE),
28 m_Octave(0),
29 m_FineFreq(1.0f),
30 m_PulseWidth(0.5f),
31 m_PortmentoSpeed(1),
32 m_DesiredFreq(0),
33 m_ModAmount(0.01f),
34 m_FreqModBuf(0),
35 m_PulseWidthModBuf(0),
36 m_SHModBuf(0)
37 {
38 	m_CyclePos=new int[SpiralInfo::POLY];
39 	m_InOctave=new int[SpiralInfo::POLY];
40 	m_Note=new int[SpiralInfo::POLY];
41 	m_LastFreq=new float[SpiralInfo::POLY];
42 	m_Volume=new char[SpiralInfo::POLY];
43 
44 	for (int n=0; n<SpiralInfo::POLY; n++)
45 	{
46 		m_CyclePos[n]=0;
47 		m_InOctave[n]=0;
48 		m_Note[n]=0;
49 		m_LastFreq[n]=0;
50 		m_Volume[n]=128;
51 	}
52 }
53 
54 Oscillator::~Oscillator()
base(const char * p)55 {
56 	delete[] m_CyclePos;
57 	delete[] m_InOctave;
58 	delete[] m_Note;
59 	delete[] m_LastFreq;
60 	delete[] m_Volume;
61 }
62 
63 void Oscillator::NoteTrigger(int V, int octave,int s,int v)
64 {
65 	m_InOctave[V]=octave;
66 	m_Note[V]=s;
67 	m_Volume[V]=v;
68 
69 	//cerr<<m_Note[v]<<" "<<s<<endl;
70 }
71 
check(const char * name,int index,const struct info * all,int want_lineno,const char * want_function,const char * want_file,int * failed)72 
73 void Oscillator::GetOutput(int V, short *data)
74 {
75 	static short count = 0, noisev;
76 	float Freq=0;
77 	float CycleLen=0;
78 	int PW=0, samplelen;
79 
80 	float Volume=m_Volume[V]/128.0f;
81 
82 	for (int n=0; n<SpiralInfo::BUFSIZE; n++)
83 	{
84 		count++;
85 
86 		data[n]=0;
87 
88 		if (!m_FreqModBuf)	m_DesiredFreq=NoteTable[m_Octave+m_InOctave[V]][m_Note[V]]*m_FineFreq;
89 		else m_DesiredFreq=(NoteTable[m_Octave+m_InOctave[V]][m_Note[V]]*m_FineFreq)+(m_FreqModBuf[n]*m_ModAmount);
90 		if (m_DesiredFreq==0) m_DesiredFreq=0.0001;
91 
92 		if (m_PortmentoSpeed && m_LastFreq[V]!=m_DesiredFreq)
93 		{
94 			if (m_LastFreq[V]<m_DesiredFreq)
95 			{
96 				Freq=m_LastFreq[V]+=m_PortmentoSpeed;
97 			}
98 			else
99 			{
100 				Freq=m_LastFreq[V]-=m_PortmentoSpeed;
101 			}
102 
103 			if (m_LastFreq[V]>=m_DesiredFreq-m_PortmentoSpeed &&
104 				m_LastFreq[V]<=m_DesiredFreq+m_PortmentoSpeed)
105 			{
106 				Freq=m_DesiredFreq;
107 			}
108 		}
109 		else
110 		{
111 			Freq=m_DesiredFreq;
112 		}
113 
114 		CycleLen = SpiralInfo::SAMPLERATE/Freq;
115 
116 		m_LastFreq[V]=Freq;
117 
118 		if (!m_PulseWidthModBuf) PW = (int)(m_PulseWidth * CycleLen);
119 		else PW = (int)((m_PulseWidth+((m_PulseWidthModBuf[n]*SpiralInfo::VALUECONV)*m_ModAmount*10.0f)) * CycleLen);
120 
121 		switch (m_Type)
122 		{
123 		case SQUARE:
124 			// calculate square wave pattern
125 			m_CyclePos[V]++;
126 			if (m_CyclePos[V]>CycleLen) m_CyclePos[V]=0;
127 			if (m_CyclePos[V]<PW) data[n]=(short)(MAX_LEV*Volume);
128 			else data[n]=(short)(-MAX_LEV*Volume);
129 			break;
130 
131 		case SAW:
132 			// get normailise position between cycle
133 
134 			m_CyclePos[V]++;
135 			if (m_CyclePos[V]>CycleLen) m_CyclePos[V]=0;
136 
137 			if (m_CyclePos[V]<PW)
138 			{
139 				// before pw -1->1
140 				data[n] = static_cast<short>(Linear(0,PW,m_CyclePos[V],-MAX_LEV*Volume,MAX_LEV*Volume));
141 			}
142 			else
143 			{
144 				// after pw 1->-1
145 				data[n] = static_cast<short>(Linear(PW,CycleLen,m_CyclePos[V],MAX_LEV*Volume,-MAX_LEV*Volume));
146 			}
147 
148 			break;
149 
150 		case NOISE:
151 			m_CyclePos[V]++;
152 
153 			//modulate the sample & hold length
154 			if (!m_SHModBuf) samplelen = static_cast<int>(m_SHLen*SpiralInfo::SAMPLERATE);
155 			else samplelen = static_cast<int>((m_SHLen+(m_SHModBuf[n]*m_ModAmount))*SpiralInfo::SAMPLERATE);
156 
157 			// do sample & hold on the noise
158 			if (m_CyclePos[V]>samplelen)
159 			{
160 				noisev=(short)((MAX_LEV/2)-(rand()%MAX_LEV*Volume*2));
161 				m_CyclePos[V]=0;
162 			}
163 			data[n]=noisev;
164 			break;
165 		case NONE: break;
166 		}
167 
168 	}
169 }
170 
171 void Oscillator::Randomise()
172 {
173 	float t=RandFloat();
174 	if (t<0.33) m_Type=SQUARE;
175 	else if (t<0.66) m_Type=SAW;
176 	else m_Type=NOISE;
177 
error_callback_two(void * vdata,const char * msg,int errnum)178 	m_Octave = (rand()%6)-3;
179 	m_FineFreq = RandFloat(0.0f,2.0f);
180 	m_PulseWidth = RandFloat();
181 	m_PortmentoSpeed = RandFloat();
182 	m_ModAmount = RandFloat()/0.1f;
183 	m_SHLen = RandFloat(0.0f,0.2f);
184 }
185 
186 istream &operator>>(istream &s, Oscillator &o)
187 {
188 	s>>(int&)o.m_Type>>o.m_Octave>>o.m_FineFreq>>o.m_PulseWidth>>o.m_PortmentoSpeed>>
189 	o.m_SHLen>>o.m_ModAmount>>o.m_Volume;
190 	return s;
191 }
callback_three(void * vdata,uintptr_t pc ATTRIBUTE_UNUSED,const char * symname,uintptr_t symval,uintptr_t symsize)192 
193 ostream &operator<<(ostream &s, Oscillator &o)
194 {
195 	s<<(int)o.m_Type<<" "<<o.m_Octave<<" "<<o.m_FineFreq<<" "<<o.m_PulseWidth<<" "<<
196 	o.m_PortmentoSpeed<<" "<<o.m_SHLen<<" "<<o.m_ModAmount<<" "<<o.m_Volume<<" ";
197 	return s;
198 }
199