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