Reacting to an audio event: loud noise

<< return to C++ examples

Principle

If you want to have a sound-based reaction, you need to retrieve the sound received by NAO’s microphones. To do so, you have to implement a particular kind of module: it must inherit from ALSoundExtractor.

ALSoundExtractor implements some key methods to help you process sound:

  • process. This method has to be redefined by the user. It is automatically called each time a sound buffer is sent, and its arguments correspond to the buffer information. You do not have to worry about any optimization, since it will automatically be called in local mode if possible.
  • startDetection. Once this method has been called, sound buffers will be sent regularly with the desired preferences to the process method.
  • stopDetection. This method stops the sound buffer sending.

The preferences for the kind of buffer to be sent are set through a proxy to ALAudioDevice.

Warning

Make sure that your sound processing function has an execution time either much smaller than the time between two sound buffers, or is thread-safe.

Example: ALSoundBasedReaction module

This section implements an example module. It will make NAO say “Hello there” each time a sufficiently loud noise is detected.

The whole example is available here: soundbasedreaction.zip

Source file:

alsoundbasedreaction.cpp

/**
* @author Gwennael Gate
* Copyright (c) Aldebaran Robotics 2010
*/

#include "alsoundbasedreaction.h"

#include <alvalue/alvalue.h>
#include <alcommon/alproxy.h>
#include <alcommon/albroker.h>
#include <iostream>
#include <fstream>

ALSoundBasedReaction::ALSoundBasedReaction(boost::shared_ptr<ALBroker> broker,
                                           const std::string& name) :
  ALSoundExtractor(broker, name)
{
  /// This line will display a description of this module on the web page of the robot
  setModuleDescription("This module launch a texttospeech command when a "
                       "sudden and significative noise is heard.");
}

void ALSoundBasedReaction::init()
{
  /// Setting up the appropriate language
  fProxyToTextToSpeech.setLanguage("English");

  audioDevice->callVoid("setClientPreferences",
                        getName(),                //Name of this module
                        16000,                    //16000 Hz requested
                        (int)FRONTCHANNEL,        //Front Channels requested
                        0                         //Deinterleaving is not needed here
                        );
#ifdef SOUNDBASEDREACTION_IS_REMOTE
  qi::Application::atStop(boost::bind(&ALSoundBasedReaction::stopDetection, this));
#endif
  startDetection();
}

ALSoundBasedReaction::~ALSoundBasedReaction()
{
  stopDetection();
}

/// This function will be automatically called by the module ALAudioDevice
/// every 170ms with the appropriate audio buffer (front channel at 16000Hz)
void ALSoundBasedReaction::process(const int & nbOfChannels,
                                   const int & nbrOfSamplesByChannel,
                                   const AL_SOUND_FORMAT * buffer,
                                   const ALValue & timeStamp)
{
  /// Compute the maximum value of the front microphone signal.
  int maxValueFront = 0;
  for(int i = 0 ; i < nbrOfSamplesByChannel ; i++)
  {
    if(buffer[i] > maxValueFront)
    {
      maxValueFront = buffer[i];
    }
  }

  /// Print it in the console
  /// (Naoqi needs to be launched in console mode to see the log)
  std::cout << "maxvalue : " << maxValueFront << std::endl;

  /// Launch a texttospeech command when it is appropriate
  if(maxValueFront > 10000)
  {
    fProxyToTextToSpeech.say("Hello there!");
  }
}

Main:

soundbasedreactionmain.cpp

/**
* @author Gwennael Gate
* Copyright (c) Aldebaran Robotics 2010
*/

#include <signal.h>
#include <boost/shared_ptr.hpp>
#include <alcommon/albroker.h>
#include <alcommon/almodule.h>
#include <alcommon/albrokermanager.h>
#include <alcommon/altoolsmain.h>

#include "alsoundbasedreaction.h"



#ifdef SOUNDBASEDREACTION_IS_REMOTE
# define ALCALL
#else
# ifdef _WIN32
#  define ALCALL __declspec(dllexport)
# else
#  define ALCALL
# endif
#endif

extern "C"
{
  ALCALL int _createModule(boost::shared_ptr<AL::ALBroker> pBroker)
  {
    // init broker with the main broker instance
    // from the parent executable
    AL::ALBrokerManager::setInstance(pBroker->fBrokerManager.lock());
    AL::ALBrokerManager::getInstance()->addBroker(pBroker);

    AL::ALModule::createModule<ALSoundBasedReaction>(pBroker, "ALSoundBasedReaction");

    return 0;
  }

  ALCALL int _closeModule()
  {
    return 0;
  }
}

#ifdef SOUNDBASEDREACTION_IS_REMOTE
int main(int argc, char *argv[])
{
  // pointer to createModule
  TMainType sig;
  sig = &_createModule;

  // call main
  ALTools::mainFunction("alsoundbasedreaction",argc, argv,sig);
}
#endif

CMakeLists.txt:

CMakeLists.txt

# Copyright (C) 2010 Aldebaran Robotics

cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR)
project(soundbasedreaction)
find_package(qibuild)

option(SOUNDBASEDREACTION_IS_REMOTE
  "module is compiled as a remote module (ON or OFF)"
  ON)

set(_srcs
    main.cpp
    alsoundbasedreaction.h
    alsoundbasedreaction.cpp
)

if(SOUNDBASEDREACTION_IS_REMOTE)
  add_definitions(" -DSOUNDBASEDREACTION_IS_REMOTE ")
  qi_create_bin(soundbasedreaction ${_srcs})
else()
  qi_create_lib(soundbasedreaction SHARED ${_srcs} SUBFOLDER naoqi)
endif()


qi_use_lib(soundbasedreaction ALCOMMON ALPROXIES ALAUDIO)