00001
00002 #ifndef TAPTAUDIO_PAIMPL_DOT_AITCH
00003 #define TAPTAUDIO_PAIMPL_DOT_AITCH
00004
00005 #include "taptaudio.h"
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifdef HAVE_CONFIG_H
00015 #include "config.h"
00016 #endif
00017
00018 #include <map>
00019 #include <SDL_thread.h>
00020 #include <limits>
00021 #include <math.h>
00022
00023 #include "sample.h"
00024
00025
00026
00027
00028
00029
00030
00031 #ifndef PAV19
00032 #include "portaudio.h"
00033 #else
00034 #include "portaudio_v19.h"
00035 #endif
00036
00037
00038 class AudioSystemImpl {
00039 private:
00040 AudioSystemImpl(const AudioSystemImpl&) {}
00041 AudioSystemImpl& operator=(const AudioSystemImpl&) {return *this;}
00042 public:
00043 typedef std::map<std::string, ASSample*> REGISTRY;
00044 static SDL_mutex *as_mutex;
00045 static SDL_mutex *registry_mutex;
00046 protected:
00047 REGISTRY registry;
00048 #ifndef PAV19
00049 PortAudioStream *stream;
00050 typedef PaTimestamp Timestamp;
00051 #else
00052 PaStream *stream;
00053 typedef PaTime Timestamp;
00054 #endif
00055 bool stopping;
00056 bool fakeMonoMic;
00057 unsigned inChannels;
00058 unsigned outChannels;
00059 double sampRate;
00060 AUDIO_FORMAT fmt;
00061
00062 unsigned iframe_size;
00063 unsigned oframe_size;
00064
00065 Recording *cur_rec;
00066 Recording *record_after_play;
00067
00068 ASSample *cur_play;
00069 unsigned long play_offset;
00070
00071
00072 virtual void doRecord(const void *inputBuffer,
00073 unsigned long framesPerBuffer);
00074
00075
00076 virtual void doPlay(void *outputBuffer,
00077 unsigned long framesPerBuffer,
00078 Timestamp outTime);
00079
00080 public:
00081
00082 virtual ~AudioSystemImpl();
00083
00084
00085 AudioSystemImpl(unsigned inputChannels = 1,
00086 unsigned outputChannels = 2,
00087 double sampleRate = 44100,
00088 AUDIO_FORMAT format = AF_Int16,
00089 int deviceIDin = 0,
00090 int deviceIDout = 0);
00091
00092
00093
00094
00095 virtual int callback(const void *inputBuffer,
00096 void *outputBuffer,
00097 unsigned long framesPerBuffer,
00098 Timestamp outTime);
00099
00100
00101
00102
00103 virtual ASSample** getSampleHolder(bool loop = false, float vol = 1.0f, unsigned* trackno = 0);
00104
00105
00106 virtual ASSample* loadSample(const std::string &name);
00107 ASSample* loadRawSample(const std::string &name, void* data, unsigned long size);
00108 bool mixSample(ASSample *samp, bool record_after, double record_size, bool loop = false, float vol = 1.0f, unsigned* trackno = 0);
00109 bool loopSample(ASSample *samp, float vol = 1.0f, unsigned* trackno = 0);
00110 bool freeSample(ASSample *samp);
00111 virtual unsigned stopSample(ASSample *samp, int trackno = -1, bool lock = true);
00112 virtual unsigned setVolume(ASSample *, float = 1.0f, int = -1) {return 0;}
00113 bool startRec(double max_seconds);
00114 bool isRecording() { return cur_rec; }
00115 ASSample* stopRec(const std::string &name, bool save = false, bool save_in_thread = false);
00116 void stop() {stopping = true;}
00117 void waitstop();
00118
00119 static void listDevices();
00120 };
00121
00122
00123
00124
00125
00126 class AudioSystemMixer : public AudioSystemImpl {
00127 protected:
00128 const unsigned tracks;
00129 struct Mix {
00130 ASSample *sam;
00131 unsigned off;
00132 float vol;
00133 bool looping;
00134 };
00135 Mix *track;
00136
00137 virtual void doPlay(void *outputBuffer,
00138 unsigned long framesPerBuffer,
00139 Timestamp outTime) = 0;
00140
00141 public:
00142 AudioSystemMixer(unsigned inputChannels = 1,
00143 unsigned outputChannels = 2,
00144 double sampleRate = 44100,
00145 AUDIO_FORMAT format = AF_Int16,
00146 unsigned ttracks = 32,
00147 int deviceIDin = 0,
00148 int deviceIDout = 0)
00149 :
00150 AudioSystemImpl(inputChannels, outputChannels, sampleRate, format, deviceIDin, deviceIDout), tracks(ttracks) {
00151 track = new Mix[tracks];
00152 for (unsigned i = 0; i < tracks; ++i)
00153 track[i].sam = 0;
00154 }
00155
00156 virtual ~AudioSystemMixer() {
00157 delete[] track;
00158 }
00159
00160 virtual ASSample** getSampleHolder(bool loop = false, float vol = 1.0f, unsigned* trackno = 0);
00161 virtual unsigned stopSample(ASSample *samp, int trackno = -1, bool lock = true);
00162 virtual unsigned setVolume(ASSample *samp, float vol = 1.0f, int trackno = -1);
00163 };
00164
00165
00166
00167
00168
00169 template <class T>
00170 class AudioSystemMixerT : public AudioSystemMixer {
00171 virtual void doPlay(void *outputBuffer,
00172 unsigned long framesPerBuffer,
00173 Timestamp outTime);
00174
00175
00176 void clipadd(T& accum, const T& val);
00177 public:
00178 AudioSystemMixerT(unsigned inputChannels = 1,
00179 unsigned outputChannels = 2,
00180 double sampleRate = 44100,
00181 AUDIO_FORMAT format = AF_Int16,
00182 unsigned ttracks = 32,
00183 int deviceIDin = 0,
00184 int deviceIDout = 0)
00185 :
00186 AudioSystemMixer(inputChannels, outputChannels, sampleRate, format, ttracks, deviceIDin, deviceIDout) {}
00187 virtual ASSample* loadSample(const std::string &name);
00188 };
00189
00190 template <class T>
00191 inline void AudioSystemMixerT<T>::clipadd(T& accum, const T& val) {
00192
00193 const T tmp = accum + val;
00194 accum = (((accum & val & ~tmp) | (~accum & ~val & tmp)) < 0) ?
00195 (accum < 0 ?
00196 std::numeric_limits<T>::min() :
00197 std::numeric_limits<T>::max()) :
00198 tmp;
00199 }
00200
00201 template <>
00202 inline void AudioSystemMixerT<float>::clipadd(float& accum, const float& val) {
00203 accum += val;
00204 }
00205
00206 template <>
00207 inline void AudioSystemMixerT<double>::clipadd(double& accum, const double& val) {
00208 accum += val;
00209 }
00210
00211 template <class T>
00212 void AudioSystemMixerT<T>::doPlay(void *outputBuffer,
00213 unsigned long framesPerBuffer,
00214 Timestamp ) {
00215 if (!outputBuffer)
00216 return;
00217
00218 T *opb = static_cast<T*>(outputBuffer);
00219 unsigned nmixed = 0;
00220 memset(outputBuffer, 0, oframe_size * framesPerBuffer);
00221
00222 for (unsigned i = 0; i < tracks; ++i) {
00223 if (track[i].sam) {
00224 Mix &m = track[i];
00225
00226 const T* ipb = static_cast<const T*>(m.sam->getBytes());
00227
00228 unsigned long nframes = m.sam->numBytes() / m.sam->getChannels() / sizeof(T);
00229
00230 unsigned &offset = m.off;
00231
00232 bool &loop = m.looping;
00233 bool v = m.vol != 1.0f;
00234
00235 if (loop || offset < nframes) {
00236 unsigned opb_offset = 0;
00237 unsigned long n;
00238 do {
00239 if (loop && offset >= nframes)
00240 offset = 0;
00241
00242 n = nframes-offset;
00243 if (n > framesPerBuffer - opb_offset)
00244 n = framesPerBuffer - opb_offset;
00245
00246 unsigned ich = m.sam->getChannels();
00247 ipb += offset*ich;
00248
00249 if (ich == 1) {
00250
00251 for (unsigned f = opb_offset; f < n; ++f) {
00252 for (unsigned c = 0; c < outChannels; ++c) {
00253 clipadd(opb[outChannels*f + c],
00254 v ? static_cast<T>(roundf(ipb[f] * m.vol))
00255 : ipb[f]);
00256 }
00257 }
00258 m.sam->mixed(n, track + i);
00259 } else if (ich == outChannels) {
00260 for (unsigned f = opb_offset; f < n*ich; ++f) {
00261 clipadd(opb[f],
00262 v ? static_cast<T>(roundf(ipb[f] * m.vol))
00263 : ipb[f]);
00264 }
00265 m.sam->mixed(n, track + i);
00266 } else {
00267
00268 }
00269 offset += n;
00270 } while (loop && (opb_offset += n) < framesPerBuffer);
00271 ++nmixed;
00272 }
00273 if (!loop && offset >= nframes) {
00274 --m.sam->refs;
00275 m.sam = 0;
00276 }
00277 }
00278 }
00279 if (nmixed == 0 && record_after_play) {
00280 cur_rec = record_after_play;
00281 record_after_play = 0;
00282 }
00283 }
00284
00285
00286 template <class T>
00287 ASSample* AudioSystemMixerT<T>::loadSample(const std::string &name) {
00288 ASSample *ret = 0;
00289
00290 SDL_mutexP(AudioSystemImpl::registry_mutex);
00291
00292 REGISTRY::iterator it = registry.find(name);
00293 if (it == registry.end()) {
00294 try {
00295 ret = new FileSampleT<T>(name, outChannels == 2);
00296
00297
00298
00299
00300 if (sampRate != ret->getSamRate()) {
00301 DODEBUG(WARNING, ("[Aw] Warning: the sample rate of %s (%fHz) differs from the current AudioSystem (%fHz)\n",
00302 name.c_str(), ret->getSamRate(), sampRate));
00303 }
00304
00305 registry.insert(REGISTRY::value_type(name, ret));
00306 } catch (const char *err) {
00307 DODEBUG(ERROR, ("[Ae] Exception caught at loadSample: %s",
00308 err));
00309 } catch (std::bad_alloc &) {
00310 DODEBUG(ERROR, ("[Ae] Not enough memory to load %s\n",
00311 name.c_str()));
00312 }
00313 } else {
00314 ret = it->second;
00315 }
00316 SDL_mutexV(AudioSystemImpl::registry_mutex);
00317 return ret;
00318 }
00319
00320
00321 #endif