move work on TinyAudio.
This commit is contained in:
@@ -1,28 +1,76 @@
|
|||||||
#include "TinyAudioExample.h"
|
#include "TinyAudioExample.h"
|
||||||
#include "../CommonInterfaces/CommonExampleInterface.h"
|
#include "../CommonInterfaces/CommonExampleInterface.h"
|
||||||
#include "../CommonInterfaces/CommonGUIHelperInterface.h"
|
#include "../CommonInterfaces/CommonGUIHelperInterface.h"
|
||||||
|
#include "Bullet3Common/b3AlignedObjectArray.h"
|
||||||
|
#include "Bullet3Common/b3HashMap.h"
|
||||||
|
|
||||||
|
|
||||||
#include "b3SoundEngine.h"
|
#include "b3SoundEngine.h"
|
||||||
#include "b3SoundSource.h"
|
#include "b3SoundSource.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
///very basic hashable string implementation, compatible with b3HashMap
|
||||||
|
struct MyHashString
|
||||||
|
{
|
||||||
|
std::string m_string;
|
||||||
|
unsigned int m_hash;
|
||||||
|
|
||||||
|
B3_FORCE_INLINE unsigned int getHash()const
|
||||||
|
{
|
||||||
|
return m_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
MyHashString(const char* name)
|
||||||
|
:m_string(name)
|
||||||
|
{
|
||||||
|
/* magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ */
|
||||||
|
static const unsigned int InitialFNV = 2166136261u;
|
||||||
|
static const unsigned int FNVMultiple = 16777619u;
|
||||||
|
|
||||||
|
/* Fowler / Noll / Vo (FNV) Hash */
|
||||||
|
unsigned int hash = InitialFNV;
|
||||||
|
|
||||||
|
for(int i = 0; m_string[i]; i++)
|
||||||
|
{
|
||||||
|
hash = hash ^ (m_string[i]); /* xor the low 8 bits */
|
||||||
|
hash = hash * FNVMultiple; /* multiply by the magic number */
|
||||||
|
}
|
||||||
|
m_hash = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool equals(const MyHashString& other) const
|
||||||
|
{
|
||||||
|
return (m_string == other.m_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
double base_frequency = 440.0;
|
||||||
|
double base_pitch = 69.0;
|
||||||
|
|
||||||
|
double MidiPitch2Frequency(double incoming_note) {
|
||||||
|
return base_frequency * pow (2.0, (incoming_note - base_pitch) / 12.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double FrequencytoMidiPitch(double incoming_frequency) {
|
||||||
|
return base_pitch + (12.0 * log(incoming_frequency / base_frequency) / log(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class TinyAudioExample : public CommonExampleInterface
|
class TinyAudioExample : public CommonExampleInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
GUIHelperInterface* m_guiHelper;
|
GUIHelperInterface* m_guiHelper;
|
||||||
|
|
||||||
|
|
||||||
b3SoundEngine m_soundEngine;
|
b3SoundEngine m_soundEngine;
|
||||||
b3SoundSource* m_soundSource;
|
int m_wavId;
|
||||||
|
|
||||||
|
b3HashMap<MyHashString,int> m_keyToSoundSource;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TinyAudioExample(struct GUIHelperInterface* helper)
|
TinyAudioExample(struct GUIHelperInterface* helper)
|
||||||
:m_guiHelper(helper),
|
:m_guiHelper(helper)
|
||||||
m_soundSource(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,21 +80,18 @@ public:
|
|||||||
|
|
||||||
virtual void initPhysics()
|
virtual void initPhysics()
|
||||||
{
|
{
|
||||||
m_soundEngine.init();
|
int numSoundSources = 8;
|
||||||
int sampleRate = m_soundEngine.getSampleRate();
|
bool useRealTimeDac = true;
|
||||||
|
|
||||||
m_soundSource = new b3SoundSource();
|
m_soundEngine.init(numSoundSources, useRealTimeDac);
|
||||||
m_soundSource->setWavFile(1,"wav/xylophone.rosewood.ff.C5B5_1.wav", sampleRate);
|
|
||||||
m_soundSource->setWavFile(0,"wav/xylophone.rosewood.ff.C5B5_1.wav", sampleRate);
|
m_wavId = m_soundEngine.loadWavFile("wav/xylophone.rosewood.ff.C5B5_1.wav");
|
||||||
m_soundSource->setOscillatorAmplitude(0,1);
|
int sampleRate = m_soundEngine.getSampleRate();
|
||||||
m_soundSource->setOscillatorAmplitude(1,1);
|
|
||||||
m_soundEngine.addSoundSource(m_soundSource);
|
|
||||||
m_soundSource->startSound();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void exitPhysics()
|
virtual void exitPhysics()
|
||||||
{
|
{
|
||||||
m_soundSource->stopSound();
|
|
||||||
m_soundEngine.exit();
|
m_soundEngine.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,37 +114,75 @@ public:
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool keyboardCallback(int key, int state)
|
virtual bool keyboardCallback(int key, int state)
|
||||||
{
|
{
|
||||||
if (key=='v' || key=='b')
|
if (key>='a' && key<='z')
|
||||||
{
|
{
|
||||||
|
char keyStr[2];
|
||||||
|
keyStr[0] = (char)key;
|
||||||
|
keyStr[1] = 0;
|
||||||
|
MyHashString hs (keyStr);
|
||||||
|
|
||||||
if (state)
|
if (state)
|
||||||
|
{
|
||||||
|
int soundSourceIndex = m_soundEngine.getAvailableSoundSource();
|
||||||
|
if (soundSourceIndex>=0)
|
||||||
{
|
{
|
||||||
if (key=='b')
|
|
||||||
{
|
|
||||||
m_soundSource->setOscillatorFrequency(0, 442);
|
|
||||||
m_soundSource->setOscillatorFrequency(1, 442);
|
|
||||||
}
|
|
||||||
if (key=='v')
|
|
||||||
{
|
|
||||||
m_soundSource->setOscillatorFrequency(0, 2*442);
|
|
||||||
m_soundSource->setOscillatorFrequency(1, 2*442);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (state==1)
|
|
||||||
{
|
|
||||||
m_soundSource->startSound();
|
|
||||||
|
|
||||||
|
int note = key-(97-58);
|
||||||
|
double freq = MidiPitch2Frequency(note);
|
||||||
|
|
||||||
|
b3SoundMessage msg;
|
||||||
|
msg.m_type = B3_SOUND_SOURCE_SINE_OSCILLATOR;
|
||||||
|
msg.m_frequency = freq;
|
||||||
|
msg.m_amplitude = .25;
|
||||||
|
|
||||||
|
//msg.m_type = B3_SOUND_SOURCE_WAV_FILE;
|
||||||
|
//msg.m_wavId = m_wavId;
|
||||||
|
|
||||||
|
m_soundEngine.startSound(soundSourceIndex, msg);
|
||||||
|
m_keyToSoundSource.insert(hs,soundSourceIndex);
|
||||||
|
//printf("soundSourceIndex:%d\n", soundSourceIndex);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
b3SoundSource* soundSource = this->m_soundSourcesPool[soundSourceIndex];
|
||||||
|
|
||||||
|
soundSource->setOscillatorFrequency(0, freq );
|
||||||
|
soundSource->setOscillatorFrequency(1, freq );
|
||||||
|
soundSource->startSound();
|
||||||
|
|
||||||
|
{
|
||||||
|
int* soundSourceIndexPtr = m_keyToSoundSource[hs];
|
||||||
|
if (soundSourceIndexPtr)
|
||||||
|
{
|
||||||
|
int newIndex = *soundSourceIndexPtr;
|
||||||
|
printf("just inserted: %d\n", newIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
} else
|
||||||
|
{
|
||||||
|
int* soundSourceIndexPtr = m_keyToSoundSource[hs];
|
||||||
|
if (soundSourceIndexPtr)
|
||||||
{
|
{
|
||||||
m_soundSource->stopSound();
|
int soundSourceIndex = *soundSourceIndexPtr;
|
||||||
|
//printf("releaseSound: %d\n", soundSourceIndex);
|
||||||
|
m_soundEngine.releaseSound(soundSourceIndex);
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
|
if (soundSourceIndex>=0)
|
||||||
|
{
|
||||||
|
printf("releasing %d\n", soundSourceIndex);
|
||||||
|
b3SoundSource* soundSource = this->m_soundSourcesPool[soundSourceIndex];
|
||||||
|
soundSource->stopSound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ b3ADSR::b3ADSR()
|
|||||||
{
|
{
|
||||||
m_target = 0.0;
|
m_target = 0.0;
|
||||||
m_value = 0.0;
|
m_value = 0.0;
|
||||||
m_attackRate = 0.001;
|
m_attackRate = 0.0001;
|
||||||
m_decayRate = 0.00001;
|
m_decayRate = 0.00001;
|
||||||
m_releaseRate = 0.005;
|
m_releaseRate = 0.0005;
|
||||||
m_sustainLevel = 0.5;
|
m_sustainLevel = 0.5;
|
||||||
m_state = ADSR_IDLE;
|
m_state = ADSR_IDLE;
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,7 @@ double b3ADSR::tick()
|
|||||||
|
|
||||||
bool b3ADSR::isIdle() const
|
bool b3ADSR::isIdle() const
|
||||||
{
|
{
|
||||||
return true;
|
return m_state == ADSR_IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void b3ADSR::keyOn()
|
void b3ADSR::keyOn()
|
||||||
|
|||||||
@@ -141,8 +141,9 @@ int b3AudioListener::tick(void *outputBuffer,void *inputBuffer1,unsigned int nBu
|
|||||||
//simple mixer
|
//simple mixer
|
||||||
if (numActiveSources)
|
if (numActiveSources)
|
||||||
{
|
{
|
||||||
outs[0] *= .3/numActiveSources;
|
|
||||||
outs[1] *= .3/numActiveSources;
|
outs[0] *= 1./4.;
|
||||||
|
outs[1] *= 1./4.;
|
||||||
}
|
}
|
||||||
|
|
||||||
*samples++ = outs[0];
|
*samples++ = outs[0];
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
#include "b3AudioListener.h"
|
#include "b3AudioListener.h"
|
||||||
#include "b3SoundSource.h"
|
#include "b3SoundSource.h"
|
||||||
#include "Bullet3Common/b3AlignedObjectArray.h"
|
#include "Bullet3Common/b3AlignedObjectArray.h"
|
||||||
|
#include "b3ReadWavFile.h"
|
||||||
|
#include "../Utils/b3ResourcePath.h"
|
||||||
|
#include "Bullet3Common/b3HashMap.h"
|
||||||
|
|
||||||
// The default real-time audio input and output buffer size. If
|
// The default real-time audio input and output buffer size. If
|
||||||
// clicks are occuring in the input and/or output sound stream, a
|
// clicks are occuring in the input and/or output sound stream, a
|
||||||
@@ -17,9 +20,17 @@ struct b3SoundEngineInternalData
|
|||||||
{
|
{
|
||||||
b3AudioListener m_listener;
|
b3AudioListener m_listener;
|
||||||
RtAudio m_dac;
|
RtAudio m_dac;
|
||||||
|
bool m_useRealTimeDac;
|
||||||
|
|
||||||
b3AlignedObjectArray<b3SoundSource*> m_soundSources;
|
b3AlignedObjectArray<b3SoundSource*> m_soundSources;
|
||||||
|
b3HashMap<b3HashInt, b3ReadWavFile*> m_wavFiles;
|
||||||
|
int m_wavFileUidGenerator;
|
||||||
|
|
||||||
|
b3SoundEngineInternalData()
|
||||||
|
: m_useRealTimeDac(false),
|
||||||
|
m_wavFileUidGenerator(123)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
b3SoundEngine::b3SoundEngine()
|
b3SoundEngine::b3SoundEngine()
|
||||||
@@ -33,49 +44,113 @@ b3SoundEngine::~b3SoundEngine()
|
|||||||
delete m_data;
|
delete m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void b3SoundEngine::init()
|
void b3SoundEngine::init(int maxNumSoundSources, bool useRealTimeDac)
|
||||||
{
|
{
|
||||||
|
for (int i = 0; i < maxNumSoundSources; i++)
|
||||||
|
{
|
||||||
|
b3SoundSource* source = new b3SoundSource();
|
||||||
|
m_data->m_soundSources.push_back(source);
|
||||||
|
m_data->m_listener.addSoundSource(source);
|
||||||
|
}
|
||||||
|
|
||||||
RtAudioFormat format = ( sizeof(double) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
|
this->m_data->m_useRealTimeDac = useRealTimeDac;
|
||||||
RtAudio::StreamParameters parameters;
|
|
||||||
parameters.deviceId = m_data->m_dac.getDefaultOutputDevice();
|
|
||||||
parameters.nChannels = 2;
|
|
||||||
|
|
||||||
unsigned int bufferFrames = RT_BUFFER_SIZE;
|
if (useRealTimeDac)
|
||||||
double sampleRate = m_data->m_listener.getSampleRate();
|
{
|
||||||
|
RtAudioFormat format = (sizeof(double) == 8) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
|
||||||
|
RtAudio::StreamParameters parameters;
|
||||||
|
parameters.deviceId = m_data->m_dac.getDefaultOutputDevice();
|
||||||
|
parameters.nChannels = 2;
|
||||||
|
|
||||||
m_data->m_dac.openStream( ¶meters, NULL, format, (unsigned int)sampleRate, &bufferFrames, &b3AudioListener::tick,
|
unsigned int bufferFrames = RT_BUFFER_SIZE;
|
||||||
(void *)m_data->m_listener.getTickData());
|
double sampleRate = m_data->m_listener.getSampleRate();
|
||||||
|
|
||||||
m_data->m_dac.startStream();
|
m_data->m_dac.openStream(¶meters, NULL, format, (unsigned int)sampleRate, &bufferFrames, &b3AudioListener::tick,
|
||||||
|
(void*)m_data->m_listener.getTickData());
|
||||||
|
|
||||||
|
m_data->m_dac.startStream();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void b3SoundEngine::exit()
|
void b3SoundEngine::exit()
|
||||||
{
|
{
|
||||||
m_data->m_dac.closeStream();
|
m_data->m_dac.closeStream();
|
||||||
|
m_data->m_useRealTimeDac = false;
|
||||||
|
|
||||||
for (int i=0;i<m_data->m_soundSources.size();i++)
|
for (int i = 0; i < m_data->m_soundSources.size(); i++)
|
||||||
{
|
{
|
||||||
m_data->m_listener.removeSoundSource(m_data->m_soundSources[i]);
|
m_data->m_listener.removeSoundSource(m_data->m_soundSources[i]);
|
||||||
|
m_data->m_soundSources[i]->stopSound();
|
||||||
delete m_data->m_soundSources[i];
|
delete m_data->m_soundSources[i];
|
||||||
}
|
}
|
||||||
m_data->m_soundSources.clear();
|
m_data->m_soundSources.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int b3SoundEngine::getAvailableSoundSource()
|
||||||
void b3SoundEngine::addSoundSource(b3SoundSource* source)
|
|
||||||
{
|
{
|
||||||
m_data->m_soundSources.push_back(source);
|
for (int i = 0; i < m_data->m_soundSources.size(); i++)
|
||||||
m_data->m_listener.addSoundSource(source);
|
{
|
||||||
|
if (m_data->m_soundSources[i]->isAvailable())
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void b3SoundEngine::removeSoundSource(b3SoundSource* source)
|
void b3SoundEngine::startSound(int soundSourceIndex, b3SoundMessage msg)
|
||||||
{
|
{
|
||||||
m_data->m_soundSources.remove(source);
|
b3SoundSource* soundSource = m_data->m_soundSources[soundSourceIndex];
|
||||||
|
switch (msg.m_type)
|
||||||
|
{
|
||||||
|
case B3_SOUND_SOURCE_SINE_OSCILLATOR:
|
||||||
|
{
|
||||||
|
soundSource->setOscillatorFrequency(0, msg.m_frequency);
|
||||||
|
soundSource->setOscillatorFrequency(1, msg.m_frequency);
|
||||||
|
soundSource->setOscillatorAmplitude(0,msg.m_amplitude);
|
||||||
|
soundSource->setOscillatorAmplitude(1,msg.m_amplitude);
|
||||||
|
soundSource->startSound();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case B3_SOUND_SOURCE_WAV_FILE:
|
||||||
|
{
|
||||||
|
b3ReadWavFile** wavFilePtr = m_data->m_wavFiles[msg.m_wavId];
|
||||||
|
if (wavFilePtr)
|
||||||
|
{
|
||||||
|
b3ReadWavFile* wavFile = *wavFilePtr;
|
||||||
|
soundSource->setWavFile(0,wavFile,getSampleRate());
|
||||||
|
soundSource->setWavFile(1,wavFile,getSampleRate());
|
||||||
|
soundSource->startSound();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void b3SoundEngine::releaseSound(int soundSourceIndex)
|
||||||
|
{
|
||||||
|
b3SoundSource* soundSource = m_data->m_soundSources[soundSourceIndex];
|
||||||
|
soundSource->stopSound();
|
||||||
}
|
}
|
||||||
|
|
||||||
int b3SoundEngine::loadWavFile(const char* fileName)
|
int b3SoundEngine::loadWavFile(const char* fileName)
|
||||||
{
|
{
|
||||||
|
char resourcePath[1024];
|
||||||
|
|
||||||
|
if (b3ResourcePath::findResourcePath(fileName, resourcePath, 1024))
|
||||||
|
{
|
||||||
|
b3ReadWavFile* wavFile = new b3ReadWavFile();
|
||||||
|
wavFile->getWavInfo(resourcePath);
|
||||||
|
wavFile->resize();
|
||||||
|
wavFile->read(0, true);
|
||||||
|
wavFile->normalize(1);
|
||||||
|
int wavUID = m_data->m_wavFileUidGenerator++;
|
||||||
|
m_data->m_wavFiles.insert(wavUID, wavFile);
|
||||||
|
return wavUID;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,5 +158,3 @@ double b3SoundEngine::getSampleRate() const
|
|||||||
{
|
{
|
||||||
return m_data->m_listener.getSampleRate();
|
return m_data->m_listener.getSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3,6 +3,20 @@
|
|||||||
|
|
||||||
#include "Bullet3Common/b3Scalar.h"
|
#include "Bullet3Common/b3Scalar.h"
|
||||||
|
|
||||||
|
struct b3SoundMessage
|
||||||
|
{
|
||||||
|
int m_type;//B3_SOUND_SOURCE_TYPE
|
||||||
|
double m_amplitude;
|
||||||
|
|
||||||
|
double m_frequency;
|
||||||
|
int m_wavId;
|
||||||
|
|
||||||
|
double m_attack;
|
||||||
|
double m_decay;
|
||||||
|
double m_sustain;
|
||||||
|
double m_release;
|
||||||
|
};
|
||||||
|
|
||||||
class b3SoundEngine
|
class b3SoundEngine
|
||||||
{
|
{
|
||||||
struct b3SoundEngineInternalData* m_data;
|
struct b3SoundEngineInternalData* m_data;
|
||||||
@@ -12,13 +26,12 @@ class b3SoundEngine
|
|||||||
b3SoundEngine();
|
b3SoundEngine();
|
||||||
virtual ~b3SoundEngine();
|
virtual ~b3SoundEngine();
|
||||||
|
|
||||||
void init();
|
void init(int maxNumSoundSources, bool useRealTimeDac);
|
||||||
void exit();
|
void exit();
|
||||||
|
|
||||||
//int createListener();
|
int getAvailableSoundSource();
|
||||||
|
void startSound(int soundSourceIndex, b3SoundMessage msg);
|
||||||
void addSoundSource(class b3SoundSource* source);
|
void releaseSound(int soundSourceIndex);
|
||||||
void removeSoundSource(class b3SoundSource* source);
|
|
||||||
|
|
||||||
int loadWavFile(const char* fileName);
|
int loadWavFile(const char* fileName);
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
#define MY2PI (2.*3.14159265)
|
#define MY2PI (2.*3.14159265)
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "../Utils/b3ResourcePath.h"
|
|
||||||
#include "Bullet3Common/b3FileUtils.h"
|
#include "Bullet3Common/b3FileUtils.h"
|
||||||
#include "b3ReadWavFile.h"
|
#include "b3ReadWavFile.h"
|
||||||
#include "b3ADSR.h"
|
#include "b3ADSR.h"
|
||||||
|
#include "b3Sound_C_Api.h"
|
||||||
|
|
||||||
struct b3SoundOscillator
|
struct b3SoundOscillator
|
||||||
{
|
{
|
||||||
@@ -62,7 +63,11 @@ struct b3SoundSourceInternalData
|
|||||||
{
|
{
|
||||||
b3SoundOscillator m_oscillators[MAX_OSCILLATORS];
|
b3SoundOscillator m_oscillators[MAX_OSCILLATORS];
|
||||||
b3ADSR m_envelope;
|
b3ADSR m_envelope;
|
||||||
b3ReadWavFile m_wavFile;
|
b3ReadWavFile* m_wavFilePtr;
|
||||||
|
b3SoundSourceInternalData()
|
||||||
|
:m_wavFilePtr(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
b3SoundSource::b3SoundSource()
|
b3SoundSource::b3SoundSource()
|
||||||
@@ -79,6 +84,7 @@ bool b3SoundSource::computeSamples(double* sampleBuffer, int numSamples, double
|
|||||||
{
|
{
|
||||||
|
|
||||||
double* outputSamples = sampleBuffer;
|
double* outputSamples = sampleBuffer;
|
||||||
|
int numActive = 0;
|
||||||
|
|
||||||
for (int i=0;i<numSamples;i++)
|
for (int i=0;i<numSamples;i++)
|
||||||
{
|
{
|
||||||
@@ -87,32 +93,45 @@ bool b3SoundSource::computeSamples(double* sampleBuffer, int numSamples, double
|
|||||||
double env = m_data->m_envelope.tick();
|
double env = m_data->m_envelope.tick();
|
||||||
if (env)
|
if (env)
|
||||||
{
|
{
|
||||||
for (int osc=0;osc<MAX_OSCILLATORS;osc++)
|
for (int osc=0;osc<MAX_OSCILLATORS;osc++)
|
||||||
|
{
|
||||||
|
if (m_data->m_oscillators[osc].m_type == 0)
|
||||||
|
{
|
||||||
|
samples[osc] += env * m_data->m_oscillators[osc].sampleSineWaveForm(sampleRate);
|
||||||
|
numActive++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_data->m_oscillators[osc].m_type == 1)
|
||||||
|
{
|
||||||
|
samples[osc] += env * m_data->m_oscillators[osc].sampleSawWaveForm(sampleRate);
|
||||||
|
numActive++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_data->m_oscillators[osc].m_type == 128)
|
||||||
|
{
|
||||||
|
int frame = 0;
|
||||||
|
double data = m_data->m_oscillators[osc].m_amplitude * m_data->m_wavFilePtr->tick(frame,&m_data->m_oscillators[osc].m_wavTicker);
|
||||||
|
samples[osc] += data;
|
||||||
|
numActive++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
{
|
{
|
||||||
if (m_data->m_oscillators[osc].m_type == 0)
|
for (int osc=0;osc<MAX_OSCILLATORS;osc++)
|
||||||
{
|
{
|
||||||
samples[osc] += env * m_data->m_oscillators[osc].sampleSineWaveForm(sampleRate);
|
if (m_data->m_oscillators[osc].m_type == 128)
|
||||||
|
{
|
||||||
|
m_data->m_oscillators[osc].m_wavTicker.finished_ = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_data->m_oscillators[osc].m_type == 1)
|
|
||||||
{
|
|
||||||
samples[osc] += env * m_data->m_oscillators[osc].sampleSawWaveForm(sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_data->m_oscillators[osc].m_type == 128)
|
|
||||||
{
|
|
||||||
int frame = 0;
|
|
||||||
double data = m_data->m_oscillators[osc].m_amplitude * m_data->m_wavFile.tick(frame,&m_data->m_oscillators[osc].m_wavTicker);
|
|
||||||
|
|
||||||
samples[osc] += data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//sample *= 1./double(MAX_OSCILLATORS);
|
//sample *= 1./double(MAX_OSCILLATORS);
|
||||||
|
|
||||||
double sampleLeft = samples[0];
|
double sampleLeft = samples[0];
|
||||||
double sampleRight = samples[1];
|
double sampleRight = samples[1];
|
||||||
|
if (sampleLeft != sampleRight)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
*outputSamples++ = sampleRight;
|
*outputSamples++ = sampleRight;
|
||||||
*outputSamples++ = sampleLeft ;
|
*outputSamples++ = sampleLeft ;
|
||||||
@@ -127,7 +146,7 @@ bool b3SoundSource::computeSamples(double* sampleBuffer, int numSamples, double
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
return true;
|
return numActive>0;
|
||||||
// return false;
|
// return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,22 +171,28 @@ void b3SoundSource::setOscillatorPhase(int oscillatorIndex, double phase)
|
|||||||
m_data->m_oscillators[oscillatorIndex].m_phase = phase;
|
m_data->m_oscillators[oscillatorIndex].m_phase = phase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool b3SoundSource::isAvailable() const
|
||||||
|
{
|
||||||
|
//available if ADSR is idle and wavticker is finished
|
||||||
|
return m_data->m_envelope.isIdle();
|
||||||
|
}
|
||||||
|
|
||||||
void b3SoundSource::startSound()
|
void b3SoundSource::startSound()
|
||||||
{
|
{
|
||||||
if (m_data->m_envelope.isIdle())
|
if (m_data->m_envelope.isIdle())
|
||||||
{
|
{
|
||||||
for (int osc=0;osc<MAX_OSCILLATORS;osc++)
|
for (int osc=0;osc<MAX_OSCILLATORS;osc++)
|
||||||
{
|
{
|
||||||
static int reset = 0;
|
m_data->m_oscillators[osc].reset();
|
||||||
printf("reset %d!\n",reset++);
|
|
||||||
if (m_data->m_oscillators[osc].m_wavTicker.finished_)
|
if (m_data->m_oscillators[osc].m_type == B3_SOUND_SOURCE_WAV_FILE)// .m_wavTicker.finished_)
|
||||||
{
|
{
|
||||||
m_data->m_oscillators[osc].reset();
|
|
||||||
//test reverse playback of wav
|
//test reverse playback of wav
|
||||||
m_data->m_oscillators[osc].m_wavTicker.rate_ *= -1;
|
//m_data->m_oscillators[osc].m_wavTicker.rate_ *= -1;
|
||||||
if (m_data->m_oscillators[osc].m_wavTicker.rate_<0)
|
if (m_data->m_oscillators[osc].m_wavTicker.rate_<0)
|
||||||
{
|
{
|
||||||
m_data->m_oscillators[osc].m_wavTicker.time_ = m_data->m_wavFile.getNumFrames()-1.;
|
m_data->m_oscillators[osc].m_wavTicker.time_ = m_data->m_wavFilePtr->getNumFrames()-1.;
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
m_data->m_oscillators[osc].m_wavTicker.time_ = 0.f;
|
m_data->m_oscillators[osc].m_wavTicker.time_ = 0.f;
|
||||||
@@ -187,18 +212,11 @@ void b3SoundSource::stopSound()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool b3SoundSource::setWavFile(int oscillatorIndex, const char* fileName, int sampleRate)
|
bool b3SoundSource::setWavFile(int oscillatorIndex, b3ReadWavFile* wavFilePtr, int sampleRate)
|
||||||
{
|
{
|
||||||
char resourcePath[1024];
|
|
||||||
|
|
||||||
if (b3ResourcePath::findResourcePath(fileName,resourcePath,1024))
|
|
||||||
{
|
{
|
||||||
|
m_data->m_wavFilePtr = wavFilePtr;
|
||||||
m_data->m_wavFile.getWavInfo(resourcePath);
|
m_data->m_oscillators[oscillatorIndex].m_wavTicker = m_data->m_wavFilePtr->createWavTicker(sampleRate);
|
||||||
m_data->m_wavFile.resize();
|
|
||||||
m_data->m_wavFile.read(0,true);
|
|
||||||
m_data->m_wavFile.normalize(1);
|
|
||||||
m_data->m_oscillators[oscillatorIndex].m_wavTicker = m_data->m_wavFile.createWavTicker(sampleRate);
|
|
||||||
|
|
||||||
// waveIn.openFile(resourcePath);
|
// waveIn.openFile(resourcePath);
|
||||||
double rate = 1.0;
|
double rate = 1.0;
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#ifndef B3_SOUND_SOURCE_H
|
#ifndef B3_SOUND_SOURCE_H
|
||||||
#define B3_SOUND_SOURCE_H
|
#define B3_SOUND_SOURCE_H
|
||||||
|
|
||||||
|
#include "b3Sound_C_Api.h"
|
||||||
|
|
||||||
|
|
||||||
class b3SoundSource
|
class b3SoundSource
|
||||||
{
|
{
|
||||||
struct b3SoundSourceInternalData* m_data;
|
struct b3SoundSourceInternalData* m_data;
|
||||||
@@ -18,11 +21,12 @@ public:
|
|||||||
void setOscillatorAmplitude(int oscillatorIndex, double amplitude);
|
void setOscillatorAmplitude(int oscillatorIndex, double amplitude);
|
||||||
void setOscillatorPhase(int oscillatorIndex, double phase);
|
void setOscillatorPhase(int oscillatorIndex, double phase);
|
||||||
|
|
||||||
bool setWavFile(int oscillatorIndex, const char* fileName, int sampleRate);
|
bool setWavFile(int oscillatorIndex, class b3ReadWavFile* wavFilePtr, int sampleRate);
|
||||||
|
|
||||||
void startSound();
|
void startSound();
|
||||||
void stopSound();
|
void stopSound();
|
||||||
|
|
||||||
|
bool isAvailable() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //B3_SOUND_SOURCE_H
|
#endif //B3_SOUND_SOURCE_H
|
||||||
|
|||||||
31
examples/TinyAudio/b3Sound_C_Api.h
Normal file
31
examples/TinyAudio/b3Sound_C_Api.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef B3_SOUND_C_API_H
|
||||||
|
#define B3_SOUND_C_API_H
|
||||||
|
|
||||||
|
//todo: create a sound C-API
|
||||||
|
|
||||||
|
//create sound engine
|
||||||
|
//destroy sound engine
|
||||||
|
//getSoundSource
|
||||||
|
//startSound
|
||||||
|
//releaseSound
|
||||||
|
//etc
|
||||||
|
|
||||||
|
enum B3_SOUND_SOURCE_TYPE
|
||||||
|
{
|
||||||
|
B3_SOUND_SOURCE_SINE_OSCILLATOR=1,
|
||||||
|
B3_SOUND_SOURCE_SAW_OSCILLATOR,
|
||||||
|
B3_SOUND_SOURCE_WAV_FILE,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif///B3_SOUND_C_API_H
|
||||||
Reference in New Issue
Block a user