Skip to content

Instantly share code, notes, and snippets.

@anselm
Created October 3, 2013 23:31
Show Gist options
  • Save anselm/6818713 to your computer and use it in GitHub Desktop.
Save anselm/6818713 to your computer and use it in GitHub Desktop.
Playing with the Goertzel algorithm... Replace the libcinder AudioInputSample main app .cpp with this... and throw in https://github.com/mpenkov/dtmf-cpp/blob/master/detect-au.cpp
#include "cinder/Cinder.h"
#if defined( CINDER_COCOA_TOUCH )
#include "cinder/app/AppCocoaTouch.h"
typedef ci::app::AppCocoaTouch AppBase;
#else
#include "cinder/app/AppBasic.h"
#include "cinder/audio/FftProcessor.h"
typedef ci::app::AppBasic AppBase;
#endif
#include "cinder/audio/Input.h"
#include <iostream>
#include <vector>
using namespace ci;
using namespace ci::app;
class AudioInputSampleApp : public AppBase {
public:
void setup();
void update();
void draw();
void drawWaveForm( float height );
#if defined(CINDER_MAC)
void drawFft();
#endif
audio::Input mInput;
std::shared_ptr<float> mFftDataRef;
audio::PcmBuffer32fRef mPcmBuffer;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// https://github.com/mpenkov/dtmf-cpp/blob/master/detect-au.cpp
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Utilize the DtmfDetector to detect tones in an AU file.
// The file must be 8KHz, PCM encoded, mono.
//
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <stdint.h>
#include "DtmfDetector.hpp"
//
// The size of the buffer we use for reading & processing the audio samples.
//
#define BUFLEN 256
DtmfDetector detector(BUFLEN);
int dtmfiter = 0;
//
// Das Goertzelizer
//
// Pass me data that is like so:
// + BUFLEN - or 256 shorts long
// + 16 bit
// + mono
// + 8KHz sample rate
// + linear PCM encoding
//
void goertzelizer(short* sbuf) {
detector.zerosIndexDialButton();
detector.dtmfDetecting(sbuf);
std::cout << dtmfiter << ": `" << detector.getDialButtonsArray() << "'" << std::endl;
dtmfiter++;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// end of https://github.com/mpenkov/dtmf-cpp/blob/master/detect-au.cpp
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int sbuf_cursor = 0;
short sbuf[BUFLEN];
void AudioInputSampleApp::drawWaveForm( float height )
{
if( ! mPcmBuffer ) {
return;
}
uint32_t bufLen = mPcmBuffer->getSampleCount();
audio::Buffer32fRef leftBuffer = mPcmBuffer->getChannelData( audio::CHANNEL_FRONT_LEFT );
//audio::Buffer32fRef rightBuffer = mPcmBuffer->getChannelData( audio::CHANNEL_FRONT_RIGHT );
int displaySize = getWindowWidth();
int endIdx = bufLen;
//only draw the last 1024 samples or less
int32_t startIdx = ( endIdx - 1024 );
startIdx = math<int32_t>::clamp( startIdx, 0, endIdx );
float scale = displaySize / (float)( endIdx - startIdx );
PolyLine<Vec2f> line;
gl::color( Color( 1.0f, 0.5f, 0.25f ) );
for( uint32_t i = startIdx, c = 0; i < endIdx; i++, c++ ) {
float y = ( ( leftBuffer->mData[i] - 1 ) * - 100 );
line.push_back( Vec2f( ( c * scale ), y ) );
}
gl::draw( line );
// we have an inbound buffer of bufLen samples recorded at 44100
// from this we want to produce an outbound buffer of 256 samples recorded at 8000
// we want to accept every 44100/8000 samples to get the target sample rate we desire
// - we do want to do a low pass filter
// we convert it to 16 bit pcm space
for(float i = 0; i < bufLen; i+= 44100.0f/8000.0f) {
short val = leftBuffer->mData[(int)i] * 32768;
// val = val * 10; // make it louder
sbuf[sbuf_cursor] = val;
sbuf_cursor++;
if(sbuf_cursor >= BUFLEN) {
goertzelizer(sbuf);
sbuf_cursor = 0;
}
}
}
#if defined(CINDER_MAC)
void AudioInputSampleApp::drawFft()
{
uint16_t bandCount = 512;
float ht = 1000.0f;
float bottom = 150.0f;
if( ! mFftDataRef ) {
return;
}
float * fftBuffer = mFftDataRef.get();
for( int i = 0; i < ( bandCount ); i++ ) {
float barY = fftBuffer[i] / bandCount * ht;
glBegin( GL_QUADS );
glColor3f( 255.0f, 255.0f, 0.0f );
glVertex2f( i * 3, bottom );
glVertex2f( i * 3 + 1, bottom );
glColor3f( 0.0f, 255.0f, 0.0f );
glVertex2f( i * 3 + 1, bottom - barY );
glVertex2f( i * 3, bottom - barY );
glEnd();
}
}
#endif
void AudioInputSampleApp::draw()
{
#if defined( CINDER_COCOA_TOUCH )
float waveFormHeight = getWindowWidth() / 2;
#else
float waveFormHeight = 100.0;
#endif
gl::setMatricesWindow( getWindowWidth(), getWindowHeight() );
gl::clear( Color( 0.1f, 0.1f, 0.1f ) );
glPushMatrix();
drawWaveForm( waveFormHeight );
#if defined(CINDER_MAC)
glTranslatef( 0.0f, 200.0f, 0.0f );
drawFft();
#endif
glPopMatrix();
}
void AudioInputSampleApp::update() {
mPcmBuffer = mInput.getPcmBuffer();
if( ! mPcmBuffer ) {
return;
}
#if defined( CINDER_MAC )
uint16_t bandCount = 512;
//presently FFT only works on OS X, not iOS
mFftDataRef = audio::calculateFft( mPcmBuffer->getChannelData( audio::CHANNEL_FRONT_LEFT ), bandCount );
#endif
}
void AudioInputSampleApp::setup() {
//iterate input devices and print their names to the console
const std::vector<audio::InputDeviceRef>& devices = audio::Input::getDevices();
for( std::vector<audio::InputDeviceRef>::const_iterator iter = devices.begin(); iter != devices.end(); ++iter ) {
console() << (*iter)->getName() << std::endl;
}
//initialize the audio Input, using the default input device
mInput = audio::Input();
//tell the input to start capturing audio
mInput.start();
}
#if defined( CINDER_COCOA_TOUCH )
CINDER_APP_COCOA_TOUCH( AudioInputSampleApp, RendererGl )
#else
CINDER_APP_BASIC( AudioInputSampleApp, RendererGl )
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment