common: prevent buffer overflow
[supercollider.git] / server / scsynth / SC_Audio_Android.cpp
blob1e5ed0c8f4a3668186f1fd63a76db0c8929d0003
1 /*
2 SuperCollider audio driver for Android
3 Copyright (c) 2010 Dan Stowell. All rights reserved.
4 Incorporating code from
5 SuperCollider real time audio synthesis system
6 Copyright (c) 2002 James McCartney. All rights reserved.
7 http://www.audiosynth.com
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "SC_CoreAudio.h"
25 #include "SC_Prototypes.h"
26 #include "SC_HiddenWorld.h"
27 #include <sys/time.h>
29 SC_AndroidJNIAudioDriver::SC_AndroidJNIAudioDriver(struct World *inWorld)
30 : SC_AudioDriver(inWorld)
34 SC_AndroidJNIAudioDriver::~SC_AndroidJNIAudioDriver()
38 bool SC_AndroidJNIAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate)
40 // Here we are setting these to the values that were originally passed in as options.
41 // In current android impl, these values came directly from java as args to scsynth_android_start().
42 *outNumSamplesPerCallback = mPreferredHardwareBufferFrameSize;
43 *outSampleRate = mPreferredSampleRate;
45 int audioDataSize = mPreferredHardwareBufferFrameSize * mWorld->mNumOutputs * sizeof(float);
46 #ifndef NDEBUG
47 scprintf("SC_AndroidJNIAudioDriver::DriverSetup: allocating %i bytes for %i frames\n", audioDataSize, mPreferredHardwareBufferFrameSize);
48 #endif
50 if(mWorld->mVerbosity >= 0){
51 scprintf("<-SC_AndroidJNIAudioDriver::Setup world %p, mPreferredHardwareBufferFrameSize %i, mPreferredSampleRate %i, outNumSamplesPerCallback %i, outSampleRate %g\n",
52 mWorld, mPreferredHardwareBufferFrameSize, mPreferredSampleRate, *outNumSamplesPerCallback, *outSampleRate);
54 return true;
57 bool SC_AndroidJNIAudioDriver::DriverStart()
59 if(mWorld->mVerbosity >= 0){
60 scprintf("SC_AndroidJNIAudioDriver::DriverStart\n");
62 // no-op, nothing to do here
63 return true;
66 bool SC_AndroidJNIAudioDriver::DriverStop()
68 if(mWorld->mVerbosity >= 0){
69 scprintf("SC_AndroidJNIAudioDriver::DriverStop\n");
72 // TODO: send a message back to java to say stop the audio loop
74 return true;
77 // NB numSamplesPassed genuinely is num samples (not num frames as sometimes in sc code)
78 void SC_AndroidJNIAudioDriver::genaudio(short* arri, int numSamplesPassed)
80 //scprintf("->SC_AndroidJNIAudioDriver::genaudio()\n");
82 World *world = mWorld;
84 int numFramesPerCallback = NumSamplesPerCallback();
85 // mOSCbuftime = oscTime; // TODO, how do we set this?
86 mFromEngine.Free();
87 mToEngine.Perform();
88 mOscPacketsToEngine.Perform();
90 int numInputs = world->mNumInputs;
91 int numOutputs = world->mNumOutputs;
93 int bufFrames = mWorld->mBufLength;
94 int numBufs = numFramesPerCallback / bufFrames;
96 #ifndef NDEBUG
97 if((numFramesPerCallback * numOutputs) != numSamplesPassed)
98 scprintf("(numFramesPerCallback * numOutputs) != numSamplesPassed, %i %i\n", numFramesPerCallback, numOutputs, numSamplesPassed);
99 #endif
101 float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames;
102 float *outBuses = mWorld->mAudioBus;
103 int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs;
104 int32 *outTouched = mWorld->mAudioBusTouched;
106 int minInputs = std::min<size_t>(numInputs, mWorld->mNumInputs);
107 int minOutputs = std::min<size_t>(numOutputs, mWorld->mNumOutputs);
109 int bufFramePos = 0;
111 int64 oscTime = mOSCbuftime;
112 int64 oscInc = mOSCincrement;
113 double oscToSamples = mOSCtoSamples;
115 // main loop
116 for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames)
118 int32 bufCounter = mWorld->mBufCounter;
119 int32 *tch;
121 // copy+touch inputs
122 tch = inTouched;
123 for (int k = 0; k < minInputs; ++k)
125 float *dst = inBuses + k * bufFrames;
126 // OK, so source is an interleaved array of ints, target is noninterleaved floats
127 for (int frame = 0; frame < bufFrames; ++frame) *dst++ = (1.f/32767.f) * (float)arri[(bufFramePos+frame) * minInputs + k];
128 *tch++ = bufCounter;
131 // run engine
132 int64 schedTime;
133 int64 nextTime = oscTime + oscInc;
134 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
135 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
136 float diffTimeFloor = floor(diffTime);
137 world->mSampleOffset = (int)diffTimeFloor;
138 world->mSubsampleOffset = diffTime - diffTimeFloor;
140 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
141 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
143 SC_ScheduledEvent event = mScheduler.Remove();
144 event.Perform();
146 world->mSampleOffset = 0;
147 world->mSubsampleOffset = 0.f;
149 World_Run(world);
151 // copy touched outputs
152 tch = outTouched;
153 for (int k = 0; k < minOutputs; ++k) {
155 // OK, so the source is noninterleaved floats, target is an interleaved array of ints
156 if (*tch++ == bufCounter) {
157 float *src = outBuses + k * bufFrames;
158 for (int frame = 0; frame < bufFrames; ++frame) arri[(bufFramePos+frame) * minOutputs + k] = (short)((*src++) * 32767.f);
159 } else {
160 for (int frame = 0; frame < bufFrames; ++frame) arri[(bufFramePos+frame) * minOutputs + k] = 0;
164 // update buffer time
165 oscTime = mOSCbuftime = nextTime;
168 mAudioSync.Signal();
172 int64 gOSCoffset = 0;
174 static inline int64 GetCurrentOSCTime()
176 struct timeval tv;
177 uint64 s, f;
178 gettimeofday(&tv, 0);
179 s = (uint64)tv.tv_sec + (uint64)kSECONDS_FROM_1900_to_1970;
180 f = (uint64)((double)tv.tv_usec * kMicrosToOSCunits);
182 return (s << 32) + f;
185 int64 oscTimeNow()
187 return GetCurrentOSCTime();
190 int32 server_timeseed()
192 int64 time = GetCurrentOSCTime();
193 return Hash((int32)(time >> 32) + Hash((int32)time));
196 void initializeScheduler()
198 gOSCoffset = GetCurrentOSCTime();