Created
October 3, 2013 23:31
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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