mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 17:01:18 +02:00
Merge branch 'master' of https://github.com/worklist/interface
This commit is contained in:
commit
610948cc18
11 changed files with 436 additions and 73 deletions
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
189
audio.cpp
189
audio.cpp
|
@ -5,6 +5,14 @@
|
||||||
// Created by Seiji Emery on 9/2/12.
|
// Created by Seiji Emery on 9/2/12.
|
||||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file audio.cpp
|
||||||
|
* Low level audio i/o portaudio wrapper.
|
||||||
|
*
|
||||||
|
* @author Seiji Emery
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -18,7 +26,25 @@ Audio::AudioData *Audio::data;
|
||||||
PaStream *Audio::stream;
|
PaStream *Audio::stream;
|
||||||
PaError Audio::err;
|
PaError Audio::err;
|
||||||
float Audio::AudioData::inputGain;
|
float Audio::AudioData::inputGain;
|
||||||
|
/**
|
||||||
|
* Audio callback used by portaudio.
|
||||||
|
* Communicates with Audio via a shared pointer to Audio::data.
|
||||||
|
* Writes input audio channels (if they exist) into Audio::data->buffer,
|
||||||
|
multiplied by Audio::data->inputGain.
|
||||||
|
* Then writes Audio::data->buffer into output audio channels, and clears
|
||||||
|
the portion of Audio::data->buffer that has been read from for reuse.
|
||||||
|
*
|
||||||
|
* @param[in] inputBuffer A pointer to an internal portaudio data buffer containing data read by portaudio.
|
||||||
|
* @param[out] outputBuffer A pointer to an internal portaudio data buffer to be read by the configured output device.
|
||||||
|
* @param[in] frames Number of frames that portaudio requests to be read/written.
|
||||||
|
(Valid size of input/output buffers = frames * number of channels (2) * sizeof data type (float)).
|
||||||
|
* @param[in] timeInfo Portaudio time info. Currently unused.
|
||||||
|
* @param[in] statusFlags Portaudio status flags. Currently unused.
|
||||||
|
* @param[in] userData Pointer to supplied user data (in this case, a pointer to Audio::data).
|
||||||
|
Used to communicate with external code (since portaudio calls this function from another thread).
|
||||||
|
* @return Should be of type PaStreamCallbackResult. Return paComplete to end the stream, or paContinue to continue (default).
|
||||||
|
Can be used to end the stream from within the callback.
|
||||||
|
*/
|
||||||
int audioCallback (const void *inputBuffer,
|
int audioCallback (const void *inputBuffer,
|
||||||
void *outputBuffer,
|
void *outputBuffer,
|
||||||
unsigned long frames,
|
unsigned long frames,
|
||||||
|
@ -30,25 +56,56 @@ int audioCallback (const void *inputBuffer,
|
||||||
float *input = (float*)inputBuffer;
|
float *input = (float*)inputBuffer;
|
||||||
float *output = (float*)outputBuffer;
|
float *output = (float*)outputBuffer;
|
||||||
|
|
||||||
if (input != NULL) {
|
#if WRITE_AUDIO_INPUT_TO_OUTPUT
|
||||||
|
if (input != NULL) {// && Audio::writeAudioInputToOutput) {
|
||||||
// combine input into data buffer
|
// 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)
|
// 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,
|
unsigned int f = (unsigned int)frames,
|
||||||
p = data->bufferPos;
|
p = data->bufferPos;
|
||||||
for (; p < data->bufferLength && f > 0; --f, ++p) {
|
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].l += (*input++) * data->inputGain;
|
||||||
data->buffer[p].r += (*input++) * data->inputGain;
|
data->buffer[p].r += (*input++) * data->inputGain;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (f > 0) {
|
if (f > 0) {
|
||||||
// handle data->buffer wraparound
|
// handle data->buffer wraparound
|
||||||
for (p = 0; f > 0; --f, ++p) {
|
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].l += (*input++) * data->inputGain;
|
||||||
data->buffer[p].r += (*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
|
// Write data->buffer into outputBuffer
|
||||||
if (data->bufferPos + frames >= data->bufferLength) {
|
if (data->bufferPos + frames >= data->bufferLength) {
|
||||||
// wraparound: write first section (end of buffer) first
|
// wraparound: write first section (end of buffer) first
|
||||||
|
@ -71,10 +128,14 @@ int audioCallback (const void *inputBuffer,
|
||||||
return paContinue;
|
return paContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
** Initializes portaudio, and creates and starts an audio stream.
|
* Initialize portaudio and start an audio stream.
|
||||||
|
* Should be called at the beginning of program exection.
|
||||||
|
* @seealso Audio::terminate
|
||||||
|
* @return Returns true if successful or false if an error occurred.
|
||||||
|
Use Audio::getError() to retrieve the error code.
|
||||||
*/
|
*/
|
||||||
void Audio::init()
|
bool Audio::init()
|
||||||
{
|
{
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
|
@ -87,7 +148,7 @@ void Audio::init()
|
||||||
2, // input channels
|
2, // input channels
|
||||||
2, // output channels
|
2, // output channels
|
||||||
paFloat32, // sample format
|
paFloat32, // sample format
|
||||||
44100, // sample rate
|
44100, // sample rate (hz)
|
||||||
256, // frames per buffer
|
256, // frames per buffer
|
||||||
audioCallback, // callback function
|
audioCallback, // callback function
|
||||||
(void*)data); // user data to be passed to callback
|
(void*)data); // user data to be passed to callback
|
||||||
|
@ -96,19 +157,25 @@ void Audio::init()
|
||||||
err = Pa_StartStream(stream);
|
err = Pa_StartStream(stream);
|
||||||
if (err != paNoError) goto error;
|
if (err != paNoError) goto error;
|
||||||
|
|
||||||
return;
|
return paNoError;
|
||||||
error:
|
error:
|
||||||
fprintf(stderr, "-- Failed to initialize portaudio --\n");
|
fprintf(stderr, "-- Failed to initialize portaudio --\n");
|
||||||
fprintf(stderr, "PortAudio error (%d): %s\n", err, Pa_GetErrorText(err));
|
fprintf(stderr, "PortAudio error (%d): %s\n", err, Pa_GetErrorText(err));
|
||||||
exit(err); // replace w/ return value error code?
|
initialized = false;
|
||||||
|
delete[] data;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
** Closes the running audio stream, and deinitializes portaudio.
|
* Close the running audio stream, and deinitialize portaudio.
|
||||||
|
* Should be called at the end of program execution.
|
||||||
|
* @return Returns true if the initialization was successful, or false if an error occured.
|
||||||
|
The error code may be retrieved by Audio::getError().
|
||||||
*/
|
*/
|
||||||
void Audio::terminate ()
|
bool Audio::terminate ()
|
||||||
{
|
{
|
||||||
if (!initialized) return;
|
if (!initialized)
|
||||||
|
return true;
|
||||||
initialized = false;
|
initialized = false;
|
||||||
// err = Pa_StopStream(stream);
|
// err = Pa_StopStream(stream);
|
||||||
// if (err != paNoError) goto error;
|
// if (err != paNoError) goto error;
|
||||||
|
@ -121,14 +188,24 @@ void Audio::terminate ()
|
||||||
err = Pa_Terminate();
|
err = Pa_Terminate();
|
||||||
if (err != paNoError) goto error;
|
if (err != paNoError) goto error;
|
||||||
|
|
||||||
return;
|
return true;
|
||||||
error:
|
error:
|
||||||
fprintf(stderr, "-- portaudio termination error --\n");
|
fprintf(stderr, "-- portaudio termination error --\n");
|
||||||
fprintf(stderr, "PortAudio error (%d): %s\n", err, Pa_GetErrorText(err));
|
fprintf(stderr, "PortAudio error (%d): %s\n", err, Pa_GetErrorText(err));
|
||||||
exit(err);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::writeAudio (unsigned int offset, unsigned int length, float *left, float *right) {
|
/**
|
||||||
|
* Write a stereo audio stream (float*) to the audio buffer.
|
||||||
|
* Values should be clamped between -1.0f and 1.0f.
|
||||||
|
* @param[in] offset Write offset from the start of the audio buffer.
|
||||||
|
* @param[in] length Length of audio channels to be read.
|
||||||
|
* @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 const *left, float const *right) {
|
||||||
|
if (data->buffer == NULL)
|
||||||
|
return;
|
||||||
if (length > data->bufferLength) {
|
if (length > data->bufferLength) {
|
||||||
fprintf(stderr, "Audio::writeAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength);
|
fprintf(stderr, "Audio::writeAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength);
|
||||||
length = data->bufferLength;
|
length = data->bufferLength;
|
||||||
|
@ -149,7 +226,17 @@ void Audio::writeAudio (unsigned int offset, unsigned int length, float *left, f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::writeTone (unsigned int offset, unsigned int length, float left, float right) {
|
/**
|
||||||
|
* Write a repeated stereo sample (float) to the audio buffer.
|
||||||
|
* Values should be clamped between -1.0f and 1.0f.
|
||||||
|
* @param[in] offset Write offset from the start of the audio buffer.
|
||||||
|
* @param[in] length Length of tone.
|
||||||
|
* @param[in] left Left component.
|
||||||
|
* @param[in] right Right component.
|
||||||
|
*/
|
||||||
|
void Audio::writeTone (unsigned int offset, unsigned int length, float const left, float const right) {
|
||||||
|
if (data->buffer == NULL)
|
||||||
|
return;
|
||||||
if (length > data->bufferLength) {
|
if (length > data->bufferLength) {
|
||||||
fprintf(stderr, "Audio::writeTone length exceeded (%d). Truncating to %d.\n", length, data->bufferLength);
|
fprintf(stderr, "Audio::writeTone length exceeded (%d). Truncating to %d.\n", length, data->bufferLength);
|
||||||
length = data->bufferLength;
|
length = data->bufferLength;
|
||||||
|
@ -170,7 +257,18 @@ void Audio::writeTone (unsigned int offset, unsigned int length, float left, flo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::addAudio (unsigned int offset, unsigned int length, float *left, float *right) {
|
/**
|
||||||
|
* Write a stereo audio stream (float*) to the audio buffer.
|
||||||
|
* Audio stream is added to the existing contents of the audio buffer.
|
||||||
|
* Values should be clamped between -1.0f and 1.0f.
|
||||||
|
* @param[in] offset Write offset from the start of the audio buffer.
|
||||||
|
* @param[in] length Length of audio channels to be read.
|
||||||
|
* @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 const *left, float const *right) {
|
||||||
|
if (data->buffer == NULL)
|
||||||
|
return;
|
||||||
if (length > data->bufferLength) {
|
if (length > data->bufferLength) {
|
||||||
fprintf(stderr, "Audio::addAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength);
|
fprintf(stderr, "Audio::addAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength);
|
||||||
length = data->bufferLength;
|
length = data->bufferLength;
|
||||||
|
@ -191,7 +289,18 @@ void Audio::addAudio (unsigned int offset, unsigned int length, float *left, flo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::addTone (unsigned int offset, unsigned int length, float left, float right) {
|
/**
|
||||||
|
* Write a repeated stereo sample (float) to the audio buffer.
|
||||||
|
* Sample is added to the existing contents of the audio buffer.
|
||||||
|
* Values should be clamped between -1.0f and 1.0f.
|
||||||
|
* @param[in] offset Write offset from the start of the audio buffer.
|
||||||
|
* @param[in] length Length of tone.
|
||||||
|
* @param[in] left Left component.
|
||||||
|
* @param[in] right Right component.
|
||||||
|
*/
|
||||||
|
void Audio::addTone (unsigned int offset, unsigned int length, float const left, float const right) {
|
||||||
|
if (data->buffer == NULL)
|
||||||
|
return;
|
||||||
if (length > data->bufferLength) {
|
if (length > data->bufferLength) {
|
||||||
fprintf(stderr, "Audio::writeTone length exceeded (%d). Truncating to %d.\n", length, data->bufferLength);
|
fprintf(stderr, "Audio::writeTone length exceeded (%d). Truncating to %d.\n", length, data->bufferLength);
|
||||||
length = data->bufferLength;
|
length = data->bufferLength;
|
||||||
|
@ -211,8 +320,14 @@ void Audio::addTone (unsigned int offset, unsigned int length, float left, float
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Clear a section of the audio buffer.
|
||||||
|
* @param[in] offset Offset from the start of the audio buffer.
|
||||||
|
* @param[in] length Length of section to clear.
|
||||||
|
*/
|
||||||
void Audio::clearAudio(unsigned int offset, unsigned int length) {
|
void Audio::clearAudio(unsigned int offset, unsigned int length) {
|
||||||
|
if (data->buffer == NULL)
|
||||||
|
return;
|
||||||
if (length > data->bufferLength) {
|
if (length > data->bufferLength) {
|
||||||
fprintf(stderr, "Audio::clearAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength);
|
fprintf(stderr, "Audio::clearAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength);
|
||||||
length = data->bufferLength;
|
length = data->bufferLength;
|
||||||
|
@ -231,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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
179
audio.h
179
audio.h
|
@ -11,8 +11,135 @@
|
||||||
|
|
||||||
#include "portaudio.h"
|
#include "portaudio.h"
|
||||||
|
|
||||||
typedef short sample_t;
|
// 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.
|
||||||
|
*
|
||||||
|
* Contains static methods that write to an internal audio buffer, which
|
||||||
|
is read from by a portaudio callback.
|
||||||
|
* Responsible for initializing and terminating portaudio. Audio::init()
|
||||||
|
and Audio::terminate() should be called at the beginning and end of
|
||||||
|
program execution.
|
||||||
|
*/
|
||||||
|
class Audio {
|
||||||
|
public:
|
||||||
|
// Initializes portaudio. Should be called at the beginning of program execution.
|
||||||
|
static bool init ();
|
||||||
|
// Deinitializes portaudio. Should be called at the end of program execution.
|
||||||
|
static bool terminate ();
|
||||||
|
|
||||||
|
// Write methods: write to internal audio buffer.
|
||||||
|
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)
|
||||||
|
*/
|
||||||
|
static void setInputGain (float gain) {
|
||||||
|
data->inputGain = gain;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the internal portaudio error code (paNoError if none).
|
||||||
|
* Use in conjunction with Audio::init() or Audio::terminate(), as it is not
|
||||||
|
impacted by any other methods.
|
||||||
|
*/
|
||||||
|
const PaError getError () { return err; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Set to true by Audio::init() and false by Audio::terminate().
|
||||||
|
* Used to prevent Audio::terminate() from deleting uninitialized memory.
|
||||||
|
*/
|
||||||
|
static bool initialized;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal audio data.
|
||||||
|
* Used to communicate with the audio callback code via a shared pointer.
|
||||||
|
*/
|
||||||
|
static struct AudioData {
|
||||||
|
/**
|
||||||
|
* Internal (stereo) audio buffer.
|
||||||
|
* Written to by Audio I/O methods and the audio callback.
|
||||||
|
* As this is a ring buffer, it should not be written to directly – thus methods
|
||||||
|
like Audio::writeAudio are provided.
|
||||||
|
*/
|
||||||
|
struct BufferFrame{
|
||||||
|
float l, r;
|
||||||
|
} *buffer, *inputBuffer;
|
||||||
|
/**
|
||||||
|
* Length of the audio buffer.
|
||||||
|
*/
|
||||||
|
const static unsigned int bufferLength = 1000;
|
||||||
|
/**
|
||||||
|
* Current position (start) within the ring buffer.
|
||||||
|
* Updated by the audio callback.
|
||||||
|
*/
|
||||||
|
unsigned int bufferPos;
|
||||||
|
/**
|
||||||
|
* Audio input gain (multiplier applied to the incoming audio stream).
|
||||||
|
* Use Audio::setInputGain() to modify this.
|
||||||
|
*/
|
||||||
|
static float inputGain;// = 1.f;
|
||||||
|
|
||||||
|
AudioData () : bufferPos(0) {
|
||||||
|
inputGain = 1.0f;
|
||||||
|
buffer = new BufferFrame[bufferLength];
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
static PaStream *stream;
|
||||||
|
/**
|
||||||
|
* Internal error code (used only by Audio::init() and Audio::terminate()).
|
||||||
|
*/
|
||||||
|
static PaError err;
|
||||||
|
|
||||||
|
Audio (); // prevent instantiation (private constructor)
|
||||||
|
|
||||||
|
friend int audioCallback (const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Audio callback called by portaudio.
|
||||||
int audioCallback (const void *inputBuffer,
|
int audioCallback (const void *inputBuffer,
|
||||||
void *outputBuffer,
|
void *outputBuffer,
|
||||||
unsigned long framesPerBuffer,
|
unsigned long framesPerBuffer,
|
||||||
|
@ -20,55 +147,5 @@ int audioCallback (const void *inputBuffer,
|
||||||
PaStreamCallbackFlags statusFlags,
|
PaStreamCallbackFlags statusFlags,
|
||||||
void *userData);
|
void *userData);
|
||||||
|
|
||||||
/*
|
|
||||||
** TODO: Docs
|
|
||||||
*/
|
|
||||||
class Audio {
|
|
||||||
public:
|
|
||||||
static void init ();
|
|
||||||
static void terminate ();
|
|
||||||
|
|
||||||
// Audio values clamped betewen -1.0f and 1.0f
|
|
||||||
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 clearAudio (unsigned int offset, unsigned int length);
|
|
||||||
|
|
||||||
static void setInputGain (float gain) {
|
|
||||||
data->inputGain = gain;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static bool initialized;
|
|
||||||
|
|
||||||
static struct AudioData {
|
|
||||||
struct BufferFrame{
|
|
||||||
float l, r;
|
|
||||||
} *buffer;
|
|
||||||
const static unsigned int bufferLength = 1000;
|
|
||||||
unsigned int bufferPos;
|
|
||||||
static float inputGain;// = 1.f;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~AudioData () {
|
|
||||||
delete[] buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
}*data;
|
|
||||||
static PaStream *stream;
|
|
||||||
static PaError err;
|
|
||||||
|
|
||||||
Audio (); // prevent instantiation (private constructor)
|
|
||||||
|
|
||||||
|
|
||||||
friend int audioCallback (const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -107,3 +107,4 @@ void field_render()
|
||||||
glEnd();
|
glEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
13
field.h
13
field.h
|
@ -9,6 +9,8 @@
|
||||||
#ifndef interface_field_h
|
#ifndef interface_field_h
|
||||||
#define interface_field_h
|
#define interface_field_h
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
// Field is a lattice of vectors uniformly distributed FIELD_ELEMENTS^(1/3) on side
|
// Field is a lattice of vectors uniformly distributed FIELD_ELEMENTS^(1/3) on side
|
||||||
|
|
||||||
const int FIELD_ELEMENTS = 1000;
|
const int FIELD_ELEMENTS = 1000;
|
||||||
|
@ -18,4 +20,15 @@ int field_value(float *ret, float *pos);
|
||||||
void field_render();
|
void field_render();
|
||||||
void field_add(float* add, float *loc);
|
void field_add(float* add, float *loc);
|
||||||
|
|
||||||
|
class Field {
|
||||||
|
public:
|
||||||
|
static void init ();
|
||||||
|
static int addTo (const glm::vec3 &pos, glm::vec3 &v);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const static unsigned int fieldSize = 1000;
|
||||||
|
const static float fieldScale; // defined in cpp – inline const float definitions not allowed in standard C++?! (allowed in C++0x)
|
||||||
|
static glm::vec3 field[fieldSize];
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
B6BDADE215F44AA5002A07DF /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6BDADD815F444C1002A07DF /* CoreAudio.framework */; };
|
B6BDADE215F44AA5002A07DF /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6BDADD815F444C1002A07DF /* CoreAudio.framework */; };
|
||||||
B6BDADE315F44AB0002A07DF /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6BDADDA15F444C9002A07DF /* AudioToolbox.framework */; };
|
B6BDADE315F44AB0002A07DF /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6BDADDA15F444C9002A07DF /* AudioToolbox.framework */; };
|
||||||
B6BDADE415F44AC7002A07DF /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6BDADDC15F444D3002A07DF /* AudioUnit.framework */; };
|
B6BDADE415F44AC7002A07DF /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6BDADDC15F444D3002A07DF /* AudioUnit.framework */; };
|
||||||
|
B6BDAE4415F6BE53002A07DF /* particle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6BDAE4315F6BE53002A07DF /* particle.cpp */; };
|
||||||
D40BDFD513404BA300B0BE1F /* GLUT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40BDFD413404BA300B0BE1F /* GLUT.framework */; };
|
D40BDFD513404BA300B0BE1F /* GLUT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40BDFD413404BA300B0BE1F /* GLUT.framework */; };
|
||||||
D40BDFD713404BB300B0BE1F /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40BDFD613404BB300B0BE1F /* OpenGL.framework */; };
|
D40BDFD713404BB300B0BE1F /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40BDFD613404BB300B0BE1F /* OpenGL.framework */; };
|
||||||
D4EE3BBC15E45FFE00EE4C89 /* SerialInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D4EE3BBB15E45FFE00EE4C89 /* SerialInterface.cpp */; };
|
D4EE3BBC15E45FFE00EE4C89 /* SerialInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D4EE3BBB15E45FFE00EE4C89 /* SerialInterface.cpp */; };
|
||||||
|
@ -46,6 +47,8 @@
|
||||||
B6BDADDA15F444C9002A07DF /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
|
B6BDADDA15F444C9002A07DF /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
|
||||||
B6BDADDC15F444D3002A07DF /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
|
B6BDADDC15F444D3002A07DF /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
|
||||||
B6BDADDE15F444DB002A07DF /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
|
B6BDADDE15F444DB002A07DF /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
|
||||||
|
B6BDAE4115F6BE4D002A07DF /* particle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = particle.h; sourceTree = "<group>"; };
|
||||||
|
B6BDAE4315F6BE53002A07DF /* particle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = particle.cpp; sourceTree = "<group>"; };
|
||||||
C6859E8B029090EE04C91782 /* test_c_plus.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = test_c_plus.1; sourceTree = "<group>"; };
|
C6859E8B029090EE04C91782 /* test_c_plus.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = test_c_plus.1; sourceTree = "<group>"; };
|
||||||
D40BDFD413404BA300B0BE1F /* GLUT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLUT.framework; path = /System/Library/Frameworks/GLUT.framework; sourceTree = "<absolute>"; };
|
D40BDFD413404BA300B0BE1F /* GLUT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLUT.framework; path = /System/Library/Frameworks/GLUT.framework; sourceTree = "<absolute>"; };
|
||||||
D40BDFD613404BB300B0BE1F /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
|
D40BDFD613404BB300B0BE1F /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
|
||||||
|
@ -99,6 +102,8 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
08FB7796FE84155DC02AAC07 /* main.cpp */,
|
08FB7796FE84155DC02AAC07 /* main.cpp */,
|
||||||
|
B6BDAE4115F6BE4D002A07DF /* particle.h */,
|
||||||
|
B6BDAE4315F6BE53002A07DF /* particle.cpp */,
|
||||||
D4EE3BC015E746E900EE4C89 /* world.h */,
|
D4EE3BC015E746E900EE4C89 /* world.h */,
|
||||||
D4EE3BC415EBD90C00EE4C89 /* network.h */,
|
D4EE3BC415EBD90C00EE4C89 /* network.h */,
|
||||||
D4EE3BC515EBD93400EE4C89 /* network.cpp */,
|
D4EE3BC515EBD93400EE4C89 /* network.cpp */,
|
||||||
|
@ -189,6 +194,7 @@
|
||||||
D4EE3BC215E761B000EE4C89 /* util.cpp in Sources */,
|
D4EE3BC215E761B000EE4C89 /* util.cpp in Sources */,
|
||||||
D4EE3BC615EBD93600EE4C89 /* network.cpp in Sources */,
|
D4EE3BC615EBD93600EE4C89 /* network.cpp in Sources */,
|
||||||
B6BDADD415F4085B002A07DF /* audio.cpp in Sources */,
|
B6BDADD415F4085B002A07DF /* audio.cpp in Sources */,
|
||||||
|
B6BDAE4415F6BE53002A07DF /* particle.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -210,6 +216,10 @@
|
||||||
"\"$(SRCROOT)\"",
|
"\"$(SRCROOT)\"",
|
||||||
/usr/local/lib,
|
/usr/local/lib,
|
||||||
);
|
);
|
||||||
|
OTHER_CPLUSPLUSFLAGS = (
|
||||||
|
"-O3",
|
||||||
|
"$(OTHER_CFLAGS)",
|
||||||
|
);
|
||||||
PRODUCT_NAME = interface;
|
PRODUCT_NAME = interface;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
|
@ -227,6 +237,10 @@
|
||||||
"\"$(SRCROOT)\"",
|
"\"$(SRCROOT)\"",
|
||||||
/usr/local/lib,
|
/usr/local/lib,
|
||||||
);
|
);
|
||||||
|
OTHER_CPLUSPLUSFLAGS = (
|
||||||
|
"-O3",
|
||||||
|
"$(OTHER_CFLAGS)",
|
||||||
|
);
|
||||||
PRODUCT_NAME = interface;
|
PRODUCT_NAME = interface;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
|
|
Binary file not shown.
|
@ -29,5 +29,19 @@
|
||||||
landmarkName = "main(int argc, char** argv)"
|
landmarkName = "main(int argc, char** argv)"
|
||||||
landmarkType = "7">
|
landmarkType = "7">
|
||||||
</FileBreakpoint>
|
</FileBreakpoint>
|
||||||
|
<FileBreakpoint
|
||||||
|
shouldBeEnabled = "No"
|
||||||
|
ignoreCount = "0"
|
||||||
|
continueAfterRunningActions = "No"
|
||||||
|
isPathRelative = "1"
|
||||||
|
filePath = "particle.cpp"
|
||||||
|
timestampString = "368498289.590653"
|
||||||
|
startingColumnNumber = "9223372036854775807"
|
||||||
|
endingColumnNumber = "9223372036854775807"
|
||||||
|
startingLineNumber = "26"
|
||||||
|
endingLineNumber = "26"
|
||||||
|
landmarkName = "ParticleSystem::simulate (float deltaTime)"
|
||||||
|
landmarkType = "5">
|
||||||
|
</FileBreakpoint>
|
||||||
</FileBreakpoints>
|
</FileBreakpoints>
|
||||||
</Bucket>
|
</Bucket>
|
||||||
|
|
2
main.cpp
2
main.cpp
|
@ -766,7 +766,7 @@ void key(unsigned char k, int x, int y)
|
||||||
field_add(add, pos);
|
field_add(add, pos);
|
||||||
}
|
}
|
||||||
if (k == 't') {
|
if (k == 't') {
|
||||||
Audio::writeTone(0, 150, 0.5f, 0.5f);
|
Audio::writeTone(0, 400, 1.0f, 0.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
67
particle.cpp
Normal file
67
particle.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
//
|
||||||
|
// particle.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Seiji Emery on 9/4/12.
|
||||||
|
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "particle.h"
|
||||||
|
|
||||||
|
void ParticleSystem::simulate (float deltaTime) {
|
||||||
|
for (unsigned int i = 0; i < particleCount; ++i) {
|
||||||
|
// Move particles
|
||||||
|
particles[i].position += particles[i].velocity * deltaTime;
|
||||||
|
|
||||||
|
// Add gravity
|
||||||
|
particles[i].velocity.y -= gravity;
|
||||||
|
|
||||||
|
// Drag: decay velocity
|
||||||
|
particles[i].velocity *= 0.99;
|
||||||
|
|
||||||
|
// Add velocity from field
|
||||||
|
//Field::addTo(particles[i].velocity);
|
||||||
|
//particles[i].velocity += Field::valueAt(particles[i].position);
|
||||||
|
|
||||||
|
if (wrapBounds) {
|
||||||
|
// wrap around bounds
|
||||||
|
if (particles[i].position.x > bounds.x)
|
||||||
|
particles[i].position.x -= bounds.x;
|
||||||
|
else if (particles[i].position.x < 0.0f)
|
||||||
|
particles[i].position.x += bounds.x;
|
||||||
|
|
||||||
|
if (particles[i].position.y > bounds.y)
|
||||||
|
particles[i].position.y -= bounds.y;
|
||||||
|
else if (particles[i].position.y < 0.0f)
|
||||||
|
particles[i].position.y += bounds.y;
|
||||||
|
|
||||||
|
if (particles[i].position.z > bounds.z)
|
||||||
|
particles[i].position.z -= bounds.z;
|
||||||
|
else if (particles[i].position.z < 0.0f)
|
||||||
|
particles[i].position.z += bounds.z;
|
||||||
|
} else {
|
||||||
|
// Bounce at bounds
|
||||||
|
if (particles[i].position.x > bounds.x
|
||||||
|
|| particles[i].position.x < 0.f) {
|
||||||
|
particles[i].velocity.x *= -1;
|
||||||
|
}
|
||||||
|
if (particles[i].position.y > bounds.y
|
||||||
|
|| particles[i].position.y < 0.f) {
|
||||||
|
particles[i].velocity.y *= -1;
|
||||||
|
}
|
||||||
|
if (particles[i].position.z > bounds.z
|
||||||
|
|| particles[i].position.z < 0.f) {
|
||||||
|
particles[i].velocity.z *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
30
particle.h
Normal file
30
particle.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// particle.h
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Seiji Emery on 9/4/12.
|
||||||
|
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef interface_particle_h
|
||||||
|
#define interface_particle_h
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
class ParticleSystem {
|
||||||
|
public:
|
||||||
|
void simulate (float deltaTime);
|
||||||
|
void draw ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Particle {
|
||||||
|
glm::vec3 position, velocity;
|
||||||
|
} *particles;
|
||||||
|
unsigned int particleCount;
|
||||||
|
|
||||||
|
glm::vec3 bounds;
|
||||||
|
const static bool wrapBounds = false;
|
||||||
|
const static float gravity = 0.0001;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue