diff --git a/carte_son_v1.cpp b/carte_son_v1.cpp new file mode 100644 index 0000000..8646491 --- /dev/null +++ b/carte_son_v1.cpp @@ -0,0 +1,19 @@ +#include +#include +#include +#include "/usr/include/alsa/asoundlib.h" + + + +int main () { +int err ; +snd_pcm_t* _capture_handle ; +const char* device = "hw:0,0" ; + +/* +hw:0,0 est plus "léger" que plughw:0,0 +*/ + +if ((err = snd_pcm_open(&_capture_handle, device,SND_PCM_STREAM_CAPTURE, 0)) < 0) fprintf(stderr, "cannot open audio device %s (%s)\n", device, snd_strerror(err)) ; +exit(1) ; +} diff --git a/echantillonnage_v1.cpp b/echantillonnage_v1.cpp new file mode 100644 index 0000000..40faa41 --- /dev/null +++ b/echantillonnage_v1.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include "/usr/include/alsa/asoundlib.h" + +int main() { +const int bufferSize = 4096 ; +short rightBuffer[bufferSize] ; +short leftBuffer[bufferSize] ; +short* bufs[2] ; +bufs[0] = rightBuffer ; +bufs[1] = leftBuffer ; +int err ; + +/****** ATENTION ********/ +snd_pcm_t* _capture_handle ; +/****** ATENTION ********/ +snd_pcm_hw_params_t* hw_params ; + +if ((err = snd_pcm_readn(_capture_handle, (void**) bufs, bufferSize)) != bufferSize) fprintf(stderr, "read from audio interface failed (%s)\n", snd_strerror(err)) ; +exit(1) ; + + +if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror(err)) ; +exit(1) ; + +if ((err = snd_pcm_hw_params_any(_capture_handle, hw_params)) < 0) fprintf(stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror(err)) ; +exit(1) ; + +if ((err = snd_pcm_hw_params_set_access(_capture_handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED)) < 0) fprintf(stderr, "cannot set access type (%s)\n", snd_strerror(err)) ; +exit(1) ; + +if ((err = snd_pcm_hw_params_set_format(_capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) fprintf(stderr, "cannot set sample format (%s)\n", snd_strerror(err)) ; +exit(1) ; + + +int soundSamplingRate=44100 ; + + +if ((err = snd_pcm_hw_params_set_rate_near(_capture_handle, hw_params, &soundSamplingRate, 0)) < 0) fprintf(stderr, "cannot set sample rate (%s)\n", snd_strerror(err)) ; +exit(1) ; + +if ((err = snd_pcm_hw_params_set_channels(_capture_handle, hw_params, 2)) < 0) fprintf(stderr, "cannot set channel count (%s)\n", snd_strerror(err)) ; +exit(1) ; + +if ((err = snd_pcm_hw_params(_capture_handle, hw_params)) < 0) fprintf(stderr, "cannot set parameters (%s)\n", snd_strerror(err)) ; +exit(1) ; + +snd_pcm_hw_params_free(hw_params) ; + +if ((err = snd_pcm_prepare(_capture_handle)) < 0) fprintf(stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror(err)) ; +exit(1) ; + +/* +On obtient alors les echantillons avec: +*/ + + +} diff --git a/localisation_v1.cpp b/localisation_v1.cpp new file mode 100644 index 0000000..1e26705 --- /dev/null +++ b/localisation_v1.cpp @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include "/usr/include/alsa/asoundlib.h" + + + + +#define SAMPLE_TYPE short + +class RunningAverage; +/** +* This class computes the direction of the source of the sound it hears. +* +* It uses 2 microphones, and compute the time of arrival difference of sound +* between them to estimate the sound source localization. +*/ +class SoundSourceLoc +/** +* Max time shift between right and left mic in number of samples. +* This typically depends on the sample rate and the distance between +* microphones. +* You can either compute this with clever formulas involving sound speed +* and microphones distance, or just try and put the max value you get with +* extreme loc of sound. Guess what I did :-) +*/ +static const int _nbSamplesMaxDiff = 13 ; +/** +* Buffer size on which we will try to locate sound. +* This is a number of samples, and depends on sample rate, and speed of +* sound loc change we want to detect. Lower values mean compute sound loc +* often, but accuracy is quite low as we compute on a very small slice of +* sound. +* Empirically, I found that computing on long sounds is better, here 4096 +* samples at 44 KHz sampling rate means about one second of sound => we +/* reevaluate sound loc every second. +* Notice that the larger the value, the most computation we do, as we time +* shift on the whole buffer. +*/ +static const int _bufferSize = 4096 ; +/** +* Take a point for sound loc is level > 105% of mean level. +* This allows to compute sound loc only for "meaningful" sounds, not +* background noise. +*/ +static const float _minLevelFactorForValidLoc = 1.05f ; +/** +* sound speed in meters per seconds +*/ +static const float _soundSpeed = 344 ; +/** +* sound sampling rate in Hz +*/ +unsigned int _soundSamplingRate ; +/** +* Distance between microphones in meters#include + +*/ +static const float _distanceBetweenMicrophones = 0.1f ; + +/** An utility to compute the running average of sound power */ +RunningAverage* _averageSoundLevel ; + +/** ALSA sound input handle */ +snd_pcm_t* _capture_handle ; + +/** sound samples input buffer */ +SAMPLE_TYPE _rightBuffer[_bufferSize] ; +SAMPLE_TYPE _leftBuffer[_bufferSize] ; + +public : +SoundSourceLoc(){ +_averageSoundLevel = new RunningAverage(50) ; +_soundSamplingRate = 44100 ; +} + +// sampling : 2 chanels, 44 KHz, 16 bits. + +/** Clean exit */ +SoundSourceLoc(){ +snd_pcm_close(_capture_handle) ; +delete _averageSoundLevel ; +} + +//** +/* Main loop : read a buffer, compute sound source localization, iterate. +*/ +void run(){ +while (true) +processNextSoundBlock() ; +} + + +/** +* This is the core of the sound source localization : it takes the +* right/left sampled sounds, and compute their differences while delaying +* one channel more and more. +* => the delay for which the difference is minimal is the real delay +* between the right/left sounds, from which we can deduce the sound source +* localization +*/ +void processNextSoundBlock(){ +SAMPLE_TYPE* bufs[2] ; +bufs[0] = _rightBuffer ; +bufs[1] = _leftBuffer ; +int err ; +if ((err = snd_pcm_readn(_capture_handle, (void**) bufs, _bufferSize)) != _bufferSize) { + fprintf(stderr, "read from audio interface failed (%s)\n", snd_strerror(err)) ; + exit(1) ; + } +} + + +// compute the sound level (i.e. "loudness" of the sound) : +SAMPLE_TYPE level = computeLevel(_rightBuffer, _leftBuffer) ; +// update the average sound level with this new measure : +_averageSoundLevel->newValue(level) ; +// relative sound level of this sample compared to average : +float relativeLevel = (float) level / (float) _averageSoundLevel->getMean() ; + + +int minDiff = INT_MAX ; +int minDiffTime = -1 ; +// ’slide’ time to find minimum of right/left sound differences +for (int t = -_nbSamplesMaxDiff ; t < _nbSamplesMaxDiff ; t++){ + // compute sum of differences as the cross-correlation-like measure : + int diff = 0 ; + for (int i = _nbSamplesMaxDiff ; i < _bufferSize - _nbSamplesMaxDiff - 1 ; i++) diff += abs(_leftBuffer[i] - _rightBuffer[i + t]) ; + if (diff < minDiff){ + minDiff = diff ; + minDiffTime = t ; + } +/// if sound is loud enough, and not an extreme (=usually false +// measure), then output it : + if ((relativeLevel > _minLevelFactorForValidLoc) && (minDiffTime > -_nbSamplesMaxDiff) && (minDiffTime < _nbSamplesMaxDiff)){ +// computation of angle depending on diff time, sampling rates, +// and geometry (thanks Mathieu from Pobot :-) ) : + float angle = -(float) asin((minDiffTime * _soundSpeed) / (_soundSamplingRate * _distanceBetweenMicrophones)) ; + cout << angle << " ;" << relativeLevel << endl ; + } + } + + + + + + +/* +* Compute average sound level (i.e. power) for left/right channels. +* +* Notice we could probably do the computation on some samples only (for +* example one over 4 samples) without loosing much accuracy here. This +* would reduce computation time. +* Also, as we are only interested in relative evolution, we could +* simplify and avoid the multiplications by just taking the mean of +* absolute values ? +*/ +SAMPLE_TYPE computeLevel(SAMPLE_TYPE right[], SAMPLE_TYPE left[]){ +float level = 0 ; +for (int i = 0 ; i < _bufferSize ; i++){ + float s = (left[i] + right[i]) / 2 ; + level += (s * s) ; + } +level /= _bufferSize ; +level = sqrt(level) ; +return (SAMPLE_TYPE) level ; + + +} + +class RunningAverage +int _nbValuesForAverage ; +int _nbValues ; +float _mean ; + +public : +RunningAverage(int nbValuesForAverage){ + _nbValuesForAverage = nbValuesForAverage ; + _mean = 0 ; + _nbValues = 0 ; +} + +void newValue(SAMPLE_TYPE v){ + if (_nbValues < _nbValuesForAverage){ + _nbValues++ ; + _mean = ((_mean * (_nbValues - 1)) + v) / (float)_nbValues ; + } + SAMPLE_TYPE getMean(){ + return (SAMPLE_TYPE) _mean ; + } +} + +int main(int argc, char *argv[]){ +SoundSourceLoc soundLoc ; +soundLoc.run() ; +}