diff --git a/audio.cpp b/audio.cpp index 26ccb19087..13f6d54ec9 100644 --- a/audio.cpp +++ b/audio.cpp @@ -8,7 +8,7 @@ /** * @file audio.cpp - * Low level audio i/o wrapper around portaudio. + * Low level audio i/o portaudio wrapper. * * @author Seiji Emery * @@ -56,25 +56,56 @@ int audioCallback (const void *inputBuffer, float *input = (float*)inputBuffer; float *output = (float*)outputBuffer; - if (input != NULL) { + #if WRITE_AUDIO_INPUT_TO_OUTPUT + if (input != NULL) {// && Audio::writeAudioInputToOutput) { // combine input into data buffer // temp variables (frames and bufferPos need to remain untouched so they can be used in the second block of code) unsigned int f = (unsigned int)frames, p = data->bufferPos; for (; p < data->bufferLength && f > 0; --f, ++p) { + #if WRITE_AUDIO_INPUT_TO_BUFFER + data->buffer[p].l += + data->inputBuffer[p].l = (*input++) * data->inputGain; + data->buffer[p].r += + data->inputBuffer[p].r = (*input++) * data->inputGain; + #else data->buffer[p].l += (*input++) * data->inputGain; data->buffer[p].r += (*input++) * data->inputGain; + #endif } if (f > 0) { // handle data->buffer wraparound for (p = 0; f > 0; --f, ++p) { + #if WRITE_AUDIO_INPUT_TO_BUFFER + data->buffer[p].l += + data->inputBuffer[p].l = (*input++) * data->inputGain; + data->buffer[p].r += + data->inputBuffer[p].r = (*input++) * data->inputGain; + #else data->buffer[p].l += (*input++) * data->inputGain; data->buffer[p].r += (*input++) * data->inputGain; + #endif + } + } + } + #elif WRITE_AUDIO_INPUT_TO_BUFFER + if (input != NULL) {// && Audio::writeAudioInputToBuffer) { + unsigned int f = (unsigned int)frames, + p = data->bufferPos; + for (; p < data->bufferLength && f > 0; --f, ++p) { + data->inputBuffer[p].l = (*input++) * data->inputGain; + data->inputBuffer[p].r = (*input++) * data->inputGain; + } + if (f > 0) { + // handle data->buffer wraparound + for (p = 0; f > 0; --f, ++p) { + data->inputBuffer[p].l = (*input++) * data->inputGain; + data->inputBuffer[p].r = (*input++) * data->inputGain; } } } - + #endif // Write data->buffer into outputBuffer if (data->bufferPos + frames >= data->bufferLength) { // wraparound: write first section (end of buffer) first @@ -143,7 +174,8 @@ error: */ bool Audio::terminate () { - if (!initialized) return; + if (!initialized) + return true; initialized = false; // err = Pa_StopStream(stream); // if (err != paNoError) goto error; @@ -171,7 +203,9 @@ error: * @param[in] left Left channel of the audio stream. * @param[in] right Right channel of the audio stream. */ -void Audio::writeAudio (unsigned int offset, unsigned int length, float *left, float *right) { +void Audio::writeAudio (unsigned int offset, unsigned int length, float const *left, float const *right) { + if (data->buffer == NULL) + return; if (length > data->bufferLength) { fprintf(stderr, "Audio::writeAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength); length = data->bufferLength; @@ -200,7 +234,9 @@ void Audio::writeAudio (unsigned int offset, unsigned int length, float *left, f * @param[in] left Left component. * @param[in] right Right component. */ -void Audio::writeTone (unsigned int offset, unsigned int length, float left, float right) { +void Audio::writeTone (unsigned int offset, unsigned int length, float const left, float const right) { + if (data->buffer == NULL) + return; if (length > data->bufferLength) { fprintf(stderr, "Audio::writeTone length exceeded (%d). Truncating to %d.\n", length, data->bufferLength); length = data->bufferLength; @@ -230,7 +266,9 @@ void Audio::writeTone (unsigned int offset, unsigned int length, float left, flo * @param[in] left Left channel of the audio stream. * @param[in] right Right channel of the audio stream. */ -void Audio::addAudio (unsigned int offset, unsigned int length, float *left, float *right) { +void Audio::addAudio (unsigned int offset, unsigned int length, float const *left, float const *right) { + if (data->buffer == NULL) + return; if (length > data->bufferLength) { fprintf(stderr, "Audio::addAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength); length = data->bufferLength; @@ -260,7 +298,9 @@ void Audio::addAudio (unsigned int offset, unsigned int length, float *left, flo * @param[in] left Left component. * @param[in] right Right component. */ -void Audio::addTone (unsigned int offset, unsigned int length, float left, float right) { +void Audio::addTone (unsigned int offset, unsigned int length, float const left, float const right) { + if (data->buffer == NULL) + return; if (length > data->bufferLength) { fprintf(stderr, "Audio::writeTone length exceeded (%d). Truncating to %d.\n", length, data->bufferLength); length = data->bufferLength; @@ -286,6 +326,8 @@ void Audio::addTone (unsigned int offset, unsigned int length, float left, float * @param[in] length Length of section to clear. */ void Audio::clearAudio(unsigned int offset, unsigned int length) { + if (data->buffer == NULL) + return; if (length > data->bufferLength) { fprintf(stderr, "Audio::clearAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength); length = data->bufferLength; @@ -304,7 +346,39 @@ void Audio::clearAudio(unsigned int offset, unsigned int length) { } } - +/** + * Read audio input into the target buffer. + * @param[in] offset Offset from the start of the input audio buffer to read from. + * @param[in] length Length of the target buffer. + * @param[out] left Left channel of the target buffer. + * @param[out] right Right channel of the target buffer. + */ +void Audio::readAudioInput (unsigned int offset, unsigned int length, float *left, float *right) { +#if WRITE_AUDIO_INPUT_TO_BUFFER + if (data->inputBuffer == NULL) + return; + if (length + offset > data->bufferLength) { + fprintf(stderr, "Audio::readAudioInput length exceeded (%d + %d). Truncating to %d + %d.\n", offset, length, offset, data->bufferLength - offset); + length = data->bufferLength - offset; + } + unsigned int p = data->bufferPos + offset; + if (p > data->bufferLength) + p -= data->bufferLength; + for (; p < data->bufferLength && length > 0; --length, ++p) { + *left++ = data->inputBuffer[p].l; + *right++ = data->inputBuffer[p].r; + } + if (length > 0) { + p = 0; + for (; length > 0; --length, ++p) { + *left++ = data->inputBuffer[p].l; + *right++ = data->inputBuffer[p].r; + } + } +#else + return; +#endif +} diff --git a/audio.h b/audio.h index 27915648dc..f626b8afde 100644 --- a/audio.h +++ b/audio.h @@ -13,6 +13,24 @@ // Note: main documentation in audio.cpp +/** + * If enabled, direct the audio callback to write the audio input buffer + * directly into the audio output buffer. + */ +#define WRITE_AUDIO_INPUT_TO_OUTPUT 1 +/** + * If enabled, create an additional buffer to store audio input + * and direct the audio callback to write the audio input to this buffer. + */ +#define WRITE_AUDIO_INPUT_TO_BUFFER 0 + +// Note: I initially used static const bools within the Audio class and normal +// 'if' blocks instead of preprocessor - under the assumption that the compiler +// would optimize out the redundant code. +// However, as that apparently did not work (for some reason or another - even +// with full compiler optimization turned on), I've switched to using preprocessor +// macros instead (which is probably faster anyways (at compile-time)). + /** * Low level audio interface. * @@ -30,12 +48,16 @@ public: static bool terminate (); // Write methods: write to internal audio buffer. - static void writeAudio (unsigned int offset, unsigned int length, float *left, float *right); - static void addAudio (unsigned int offset, unsigned int length, float *left, float *right); - static void writeTone (unsigned int offset, unsigned int length, float left, float right); - static void addTone (unsigned int offset, unsigned int length, float left, float right); + static void writeAudio (unsigned int offset, unsigned int length, float const *left, float const *right); + static void addAudio (unsigned int offset, unsigned int length, float const *left, float const *right); + static void writeTone (unsigned int offset, unsigned int length, float const left, float const right); + static void addTone (unsigned int offset, unsigned int length, float const left, float const right); static void clearAudio (unsigned int offset, unsigned int length); + // Read data from internal 'input' audio buffer to an external audio buffer. + // (*only* works if WRITE_AUDIO_INPUT_TO_BUFFER is enabled). + static void readAudioInput (unsigned int offset, unsigned int length, float *left, float *right); + /** * Set the audio input gain. (multiplier applied to mic input) */ @@ -69,7 +91,7 @@ private: */ struct BufferFrame{ float l, r; - } *buffer; + } *buffer, *inputBuffer; /** * Length of the audio buffer. */ @@ -88,14 +110,20 @@ private: AudioData () : bufferPos(0) { inputGain = 1.0f; buffer = new BufferFrame[bufferLength]; - for (unsigned int i = 0; i < bufferLength; ++i) { - buffer[i].l = buffer[i].r = 0; - } + memset((float*)buffer, 0, sizeof(float) * bufferLength * 2); + #if WRITE_AUDIO_INPUT_TO_BUFFER + inputBuffer = new BufferFrame[bufferLength]; + memset((float*)inputBuffer, 0, sizeof(float) * bufferLength * 2); + #else + inputBuffer = NULL; + #endif } ~AudioData () { delete[] buffer; + #if WRITE_AUDIO_INPUT_TO_BUFFER + delete[] inputBuffer; + #endif } - }*data; /** * Internal audio stream handle. diff --git a/interface.xcodeproj/project.pbxproj b/interface.xcodeproj/project.pbxproj index 0a0a767709..8380081120 100644 --- a/interface.xcodeproj/project.pbxproj +++ b/interface.xcodeproj/project.pbxproj @@ -216,6 +216,10 @@ "\"$(SRCROOT)\"", /usr/local/lib, ); + OTHER_CPLUSPLUSFLAGS = ( + "-O3", + "$(OTHER_CFLAGS)", + ); PRODUCT_NAME = interface; }; name = Debug; @@ -233,6 +237,10 @@ "\"$(SRCROOT)\"", /usr/local/lib, ); + OTHER_CPLUSPLUSFLAGS = ( + "-O3", + "$(OTHER_CFLAGS)", + ); PRODUCT_NAME = interface; }; name = Release; diff --git a/interface.xcodeproj/project.xcworkspace/xcuserdata/Seiji.xcuserdatad/UserInterfaceState.xcuserstate b/interface.xcodeproj/project.xcworkspace/xcuserdata/Seiji.xcuserdatad/UserInterfaceState.xcuserstate index ffea69364a..de265ecd95 100644 Binary files a/interface.xcodeproj/project.xcworkspace/xcuserdata/Seiji.xcuserdatad/UserInterfaceState.xcuserstate and b/interface.xcodeproj/project.xcworkspace/xcuserdata/Seiji.xcuserdatad/UserInterfaceState.xcuserstate differ