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"
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);
47 scprintf("SC_AndroidJNIAudioDriver::DriverSetup: allocating %i bytes for %i frames\n", audioDataSize
, mPreferredHardwareBufferFrameSize
);
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
);
57 bool SC_AndroidJNIAudioDriver::DriverStart()
59 if(mWorld
->mVerbosity
>= 0){
60 scprintf("SC_AndroidJNIAudioDriver::DriverStart\n");
62 // no-op, nothing to do here
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
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?
88 mOscPacketsToEngine
.Perform();
90 int numInputs
= world
->mNumInputs
;
91 int numOutputs
= world
->mNumOutputs
;
93 int bufFrames
= mWorld
->mBufLength
;
94 int numBufs
= numFramesPerCallback
/ bufFrames
;
97 if((numFramesPerCallback
* numOutputs
) != numSamplesPassed
)
98 scprintf("(numFramesPerCallback * numOutputs) != numSamplesPassed, %i %i\n", numFramesPerCallback
, numOutputs
, numSamplesPassed
);
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
);
111 int64 oscTime
= mOSCbuftime
;
112 int64 oscInc
= mOSCincrement
;
113 double oscToSamples
= mOSCtoSamples
;
116 for (int i
= 0; i
< numBufs
; ++i
, mWorld
->mBufCounter
++, bufFramePos
+= bufFrames
)
118 int32 bufCounter
= mWorld
->mBufCounter
;
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
];
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();
146 world
->mSampleOffset
= 0;
147 world
->mSubsampleOffset
= 0.f
;
151 // copy touched outputs
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
);
160 for (int frame
= 0; frame
< bufFrames
; ++frame
) arri
[(bufFramePos
+frame
) * minOutputs
+ k
] = 0;
164 // update buffer time
165 oscTime
= mOSCbuftime
= nextTime
;
172 int64 gOSCoffset
= 0;
174 static inline int64
GetCurrentOSCTime()
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
;
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();