Skip to content

Instantly share code, notes, and snippets.

@henrikno
Created May 24, 2013 18:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save henrikno/5645669 to your computer and use it in GitHub Desktop.
Save henrikno/5645669 to your computer and use it in GitHub Desktop.
Sound + FT-example
#include <GL/glew.h>
#include <Curio.h>
#include <iostream>
#include <portaudio.h>
using namespace std;
float fspec_left[512];
float fspec_right[512];
const int SAMPLE_RATE = 44100;
struct paPlayData {
float *buffer;
unsigned int pos;
unsigned int length;
int channelCount;
};
float volume = 1.0;
int paPlay(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) {
paPlayData *data = (paPlayData*)userData;
float *out = (float*)outputBuffer;
float a = (float)data->pos / data->length;
float b = (float)data->pos / SAMPLE_RATE;
float c = (float)data->length / SAMPLE_RATE;
//std::cout << a << "\t" << b << "\t" << c << std::endl;
for (unsigned int i = 0; i < framesPerBuffer; ++i) {
if (data->pos >= data->length) {
std::cout << "end\n";
return 1;
}
for (int c = 0; c < data->channelCount; c++) {
*out = data->buffer[data->pos] * volume;
out++;
data->pos++;
}
}
return 0;
}
// Input samples, output amplitude per frequency bucket
void DFT(float *inputBuffer, float *outputBuffer, int framesize) {
const int partials = 512;
float aa[partials];
float bb[partials];
for (int i = 0; i < partials; i++) {
aa[i] = 0;
bb[i] = 0;
}
int hfs = framesize/2;
float pd = M_PI/hfs;
for (int i = 0; i < framesize; i++) {
float w = inputBuffer[i];
int im = i - hfs;
for (int h = 0; h < partials; h++) {
float th = (pd*(h+1))*im;
aa[h] += w*cos(th);
bb[h] += w*sin(th);
}
}
for (int h = 0; h < partials; h++)
outputBuffer[h] = sqrt(aa[h] * aa[h] + bb[h] * bb[h]) / hfs;
}
void FFTTest(float *inputBuffer, float *spec, int length, int channelCount) {
float *left = new float[length];
float *right = new float[length];
int z = 0;
for (int i = 0; i < length; ++i) {
left[i] = inputBuffer[z++];
if (channelCount == 2) {
right[i] = inputBuffer[z++];
}
}
// Hann window
for (int i = 0; i < length; i++) {
left[i] *= 0.50 - 0.50 * cos(2 * M_PI * i / (length - 1));
right[i] *= 0.50 - 0.50 * cos(2 * M_PI * i / (length - 1));
}
DFT(left, fspec_left, length);
DFT(right, fspec_right, length);
delete[] left;
delete[] right;
}
void Spectrum_Draw() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, 800.0/600.0, 0.1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,3,3, 0,-3,-3, 0,1,0);
int length = 512;
float zz = 1.0;
glScalef(zz, zz, zz);
glDisable(GL_LIGHTING);
glColor3f(1,1,0);
glBegin(GL_LINE_STRIP);
float step = 1.0/128.0;
for (int i = 2; i < length/2; ++i) {
float x = -1.0 + step * i;
glVertex2f(x, fspec_left[i]*5.0);
}
glEnd();
glColor3f(1,1,0);
glBegin(GL_LINE_STRIP);
for (int i = 2; i < length/2; ++i) {
float x = -1.0 + step * i;
glVertex2f(x, -fspec_right[i]*5.0);
}
glEnd();
}
int main() {
Window window(800, 600);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
PortAudio audio;
SoundBuffer sound;
sound.LoadFromFile("../Resources/sound/AttentionGrabber.ogg");
sound.Print();
paPlayData data;
data.buffer = &sound.buffer[0];
data.pos = 0;
data.length = sound.buffer.size();
data.channelCount = sound.channels;
audio.OpenStream(paPlay, &data);
audio.Start();
float time = 0.0;
while (window.IsOpen()) {
Event event;
while (window.PollEvent(event)) {}
if (window.IsKeyPressed(Keyboard::Escape))
break;
time += 0.01;
if (data.pos <= data.length - 512) {
FFTTest(data.buffer + data.pos, 0, 512, sound.channels);
}
glEnable(GL_LIGHTING);
curio::clear();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, 800.0/600.0, 0.1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(4,4,4, 0,0,0, 0,1,0);
float lpos[] = {10,6,5,1.0};
glLightfv(GL_LIGHT0, GL_POSITION, lpos);
float a = 90.0*fspec_left[1];
float b = 5*fspec_left[10];
glTranslatef(0, b, 0);
glRotatef(a, 1,1,1);
glColor3f(1,1,1);
DrawCube();
Spectrum_Draw();
window.Display();
}
audio.Stop();
audio.Close();
}
#include "PortAudio.h"
#include <portaudio.h>
#include <cstdio>
float spec_left[512];
float spec_right[512];
PortAudio::PortAudio() {
PaError err;
err = Pa_Initialize();
if (err != paNoError) {
printf("PortAudio error: %s\n", Pa_GetErrorText(err));
throw PortAudioException(Pa_GetErrorText(err));
}
isPlaying = false;
sample_rate = 44100;
}
PortAudio::~PortAudio() {
PaError err;
err = Pa_Terminate();
if (err != paNoError) {
printf("PortAudio error: %s\n", Pa_GetErrorText(err));
}
}
void PortAudio::OpenStream(PaStreamCallback callback, void *data) {
/* Open an audio I/O stream. */
PaError err;
err = Pa_OpenDefaultStream( &stream,
0, /* no input channels */
2, /* stereo output */
paFloat32, /* 32 bit floating point output */
sample_rate,
paFramesPerBufferUnspecified, /* frames per buffer, i.e. the number
of sample frames that PortAudio will
request from the callback. Many apps
may want to use
paFramesPerBufferUnspecified, which
tells PortAudio to pick the best,
possibly changing, buffer size.*/
callback, /* this is your callback function */
data ); /*This is a pointer that will be passed to
your callback*/
if (err != paNoError) {
throw PortAudioException(Pa_GetErrorText(err));
}
}
void PortAudio::Start() {
if (!isPlaying) {
PaError err;
err = Pa_StartStream(stream);
if (err != paNoError) {
throw PortAudioException(Pa_GetErrorText(err));
}
isPlaying = true;
}
}
void PortAudio::Stop() {
if (isPlaying) {
PaError err;
err = Pa_StopStream(stream);
if (err != paNoError) {
throw PortAudioException(Pa_GetErrorText(err));
}
isPlaying = false;
}
}
void PortAudio::Close() {
PaError err;
err = Pa_CloseStream(stream);
if (err != paNoError) {
throw PortAudioException(Pa_GetErrorText(err));
}
}
bool PortAudio::IsPlaying() {
return isPlaying;
}
#pragma once
#include <stdexcept>
typedef void PaStream;
typedef double PaTime;
typedef unsigned long PaStreamCallbackFlags;
struct PaStreamCallbackTimeInfo;
typedef int PaStreamCallback(
const void *input, void *output,
unsigned long frameCount,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData );
class PortAudioException : public std::runtime_error {
public:
PortAudioException(std::string what)
: std::runtime_error(what) {}
};
class PortAudio
{
public:
PortAudio();
virtual ~PortAudio();
void OpenStream(PaStreamCallback callback, void *data);
void Start();
void Stop();
void Close();
bool IsPlaying();
private:
PaStream *stream;
bool isPlaying;
int sample_rate;
};
#include "SoundBuffer.h"
#include <stb_vorbis.h>
#include <iostream>
#include <string>
#include <cassert>
#include <cstdlib>
SoundBuffer::SoundBuffer()
: channels(0), sample_rate(0), samples(0), actual_samples(0), data_size(0)
{
}
SoundBuffer::~SoundBuffer()
{
}
void SoundBuffer::LoadFromFile(std::string filename) {
int error = 0;
struct stb_vorbis *vorb = stb_vorbis_open_filename((char*)filename.c_str(), &error, NULL);
if (error != 0) {
std::cout << "Error: " << error << std::endl;
}
assert(vorb != NULL);
stb_vorbis_info info = stb_vorbis_get_info(vorb);
channels = info.channels;
sample_rate = info.sample_rate;
samples = stb_vorbis_stream_length_in_samples(vorb);
float seconds = samples / (float) info.sample_rate;
buffer.resize(samples*channels, 0.0f);
actual_samples = stb_vorbis_get_samples_float_interleaved(vorb, info.channels, &buffer[0], samples*channels);
buffer.resize(actual_samples * info.channels);
}
void SoundBuffer::LoadFromSamples(float *samples, size_t sampleCount, int channelCount, int sampleRate) {
assert(samples);
assert(sampleCount > 0);
assert(channelCount > 0);
assert(sampleRate > 0);
buffer.assign(samples, samples + sampleCount);
this->samples = sampleCount;
channels = channelCount;
sample_rate = sampleRate;
data_size = sizeof(float) * channels * this->samples;
}
int SoundBuffer::GetSampleOffset() {
return position;
}
void SoundBuffer::Print() {
std::cout << "Channels: " << channels << "\n";
std::cout << "Sample rate: " << sample_rate << "\n";
std::cout << "Samples: " << samples << "\n";
std::cout << "Actual samples: " << actual_samples << "\n";
std::cout << "Length: " << ((float)samples / sample_rate) << " s" << "\n";
std::cout << "Data size: " << data_size << std::endl;
}
#pragma once
#include <string>
#include <vector>
class SoundBuffer {
public:
SoundBuffer();
~SoundBuffer();
void LoadFromFile(std::string filename);
void LoadFromSamples(float *samples, size_t sampleCount, int channelCount, int sampleRate);
int GetSampleOffset();
void Print();
public:
std::vector<float> buffer;
int channels;
int sample_rate;
int samples;
int actual_samples;
int data_size;
int position;
unsigned int source;
unsigned int albuffer;
};
@Salamandar
Copy link

What is Curio ? And why stb_vorbis ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment