1 /* $Id: SquareWaveSource.cpp,v 1.1 2012/07/08 00:45:59 sarrazip Exp $
2
3 flatzebra - SDL-based sound renderer
4 Copyright (C) 2011 Pierre Sarrazin <http://sarrazip.com/>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public
17 License along with this program; if not, write to the Free
18 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20 */
21
22 #include <roundbeetle/SquareWaveSource.h>
23 #include <roundbeetle/FrequencyFunction.h>
24
25
26 using namespace roundbeetle;
27
28
29 static size_t
getNumSamples(float durationInSeconds)30 getNumSamples(float durationInSeconds)
31 {
32 if (durationInSeconds == 0)
33 return size_t(-1);
34 double numSamples = double(durationInSeconds) * double(SoundRenderer::freq());
35 return numSamples <= size_t(-1) ? size_t(numSamples) : size_t(-1);
36 }
37
38
SquareWaveSource(float _freq,float _linVol,float _durationInSeconds)39 SquareWaveSource::SquareWaveSource(float _freq, float _linVol, float _durationInSeconds)
40 : sampleCounter(0),
41 samplesInPeriodCounter(0),
42 maxNumSamples(getNumSamples(_durationInSeconds)),
43 samplesPerPeriod(0),
44 frequencyFunction(NULL),
45 pendingSamplesPerPeriod(0),
46 sampleValue(Sint16(_linVol * 32767))
47 {
48 assert(_linVol >= 0 && _linVol <= 1);
49 assert(_durationInSeconds >= 0);
50 assert(_durationInSeconds < float(size_t(-1)) / SoundRenderer::freq()); // max allowed duration
51
52 setFrequency(_freq); // initializes pendingSamplesPerPeriod
53 samplesPerPeriod = pendingSamplesPerPeriod;
54 assert(samplesPerPeriod > 0);
55 }
56
57
SquareWaveSource(FrequencyFunction & _frequencyFunction,float _linVol,float _durationInSeconds)58 SquareWaveSource::SquareWaveSource(FrequencyFunction &_frequencyFunction, float _linVol, float _durationInSeconds)
59 : sampleCounter(0),
60 samplesInPeriodCounter(0),
61 maxNumSamples(getNumSamples(_durationInSeconds)),
62 samplesPerPeriod(0),
63 frequencyFunction(&_frequencyFunction),
64 pendingSamplesPerPeriod(0),
65 sampleValue(Sint16(_linVol * 32767))
66 {
67 assert(_linVol >= 0 && _linVol <= 1);
68 assert(_durationInSeconds >= 0);
69 assert(_durationInSeconds < float(size_t(-1)) / SoundRenderer::freq()); // max allowed duration
70
71 samplesPerPeriod = frequencyFunction->getNumSamplesPerPeriod(0);
72 assert(samplesPerPeriod > 0);
73 }
74
75
76 void
setFrequency(float newFreq)77 SquareWaveSource::setFrequency(float newFreq)
78 {
79 if (newFreq < 20 || newFreq > 20000)
80 newFreq = 20;
81
82 size_t s = size_t(SoundRenderer::freq() / newFreq);
83 assert(s > 0);
84
85 AutoLocker a(SoundRenderer::getMutex()); // lock mutex under which getSamples() is called
86 pendingSamplesPerPeriod = s;
87 frequencyFunction = NULL;
88 }
89
90
91 size_t //virtual
getSamples(Sint16 * dest,size_t numRequested)92 SquareWaveSource::getSamples(Sint16 *dest, size_t numRequested)
93 {
94 /*std::cout << "SquareWaveSource::getSamples(" << dest << ", " << numRequested
95 << "): maxNumSamples=" << maxNumSamples
96 << ", sampleCounter=" << sampleCounter
97 << std::endl;*/
98
99 if (dest == NULL)
100 return 0;
101
102 size_t numSamplesLeft = maxNumSamples - sampleCounter;
103 size_t numDelivered = std::min(numRequested, numSamplesLeft);
104 for (size_t i = 0; i < numDelivered; ++i, ++sampleCounter)
105 {
106 dest[i] = (samplesInPeriodCounter < samplesPerPeriod / 2 ? + sampleValue : - sampleValue);
107
108 ++samplesInPeriodCounter;
109 if (samplesInPeriodCounter == samplesPerPeriod) // if complete period done
110 {
111 if (frequencyFunction != NULL)
112 samplesPerPeriod = frequencyFunction->getNumSamplesPerPeriod(sampleCounter);
113 else
114 samplesPerPeriod = pendingSamplesPerPeriod; // change to newly requested frequency
115
116 samplesInPeriodCounter = 0; // start new period
117 }
118 }
119
120 return numDelivered;
121 }
122
123
124 bool //virtual
isFinished() const125 SquareWaveSource::isFinished() const
126 {
127 return sampleCounter >= maxNumSamples;
128 }
129
130
131 bool //virtual
rewind()132 SquareWaveSource::rewind()
133 {
134 sampleCounter = 0;
135 return true;
136 }
137