Sound playback

<< return to examples index

Overview

This example module ALSoundPlayback sends sound to NAO’s loudspeakers.

This is a local module, it must be cross-compiled and sent to the robot.

Downloads

Whole module

soundplayback.zip

Header: alsoundplayback.h

alsoundplayback.h

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

#ifndef SOUNDPLAYBACK_H
#define SOUNDPLAYBACK_H

#include <boost/shared_ptr.hpp>
#include <alcommon/almodule.h>

namespace AL
{
  class ALBroker;
}

class ALSoundPlayback : public AL::ALModule
{
  struct wavheader
  {
    char chunkID[4];
    long chunkSize;
    char format[4];
    char subchunk1ID[4];
    long subchunk1Size;
    unsigned short audioFormat;
    unsigned short nbOfChannels;
    unsigned long sampleRate;
    unsigned long byteRate;
    unsigned short blockAlign;
    unsigned short bitsPerSample;
    char subchunk2ID[4];
    long subchunk2Size;
  };

public:
  ALSoundPlayback(boost::shared_ptr<AL::ALBroker> pBroker, const std::string& pName);

  virtual ~ALSoundPlayback();

  void playWavFile(const std::string &pFileName);

private:

  boost::shared_ptr <AL::ALProxy> audioDeviceProxy;
};
#endif

Source: alsoundplayback.cpp

alsoundplayback.cpp

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

#include "alsoundplayback.h"

#include <iostream>
#include <alcommon/alproxy.h>
#include <boost/shared_ptr.hpp>
#include <alcommon/albroker.h>
#include <alcommon/almodule.h>

using namespace AL;

ALSoundPlayback::ALSoundPlayback(boost::shared_ptr<ALBroker> pBroker, const std::string& pName ): ALModule(pBroker, pName )
{
  setModuleDescription("An example of how to send sound onto the nao's loudspeakers.");

  /// Define callable methods with there description
  functionName("playWavFile",
               getName(),
               "sends the content of a wav file of a remote desktop onto the nao's loudspeakers ");

  addParam("pFileName", "Name of twav file to play");
  BIND_METHOD(ALSoundPlayback::playWavFile);

  audioDeviceProxy = getParentBroker()->getProxy("ALAudioDevice");
}

ALSoundPlayback::~ALSoundPlayback()
{

}

void ALSoundPlayback::playWavFile(const std::string &pFileName)
{
  /// Maximum buffer size that ALAudioDevice can send
  const int outputBufferSize = 16384;
  /// Number of output channels on Nao
  const int numberOfOutputChannels = 2;
  FILE *fInputWavFile;

  /// Opening of the input file
  if((fInputWavFile = fopen(pFileName.c_str(), "rb" )) == NULL)
  {
    throw AL::ALError("ALSoundProcessing",
                      "playWavFile()",
                      "Failed to open input sound file.");
  }

  /// Reading of the wav header
  wavheader * wavHeader = new wavheader;
  fread(wavHeader,1,44,fInputWavFile);

  unsigned short nbOfChannels = wavHeader->nbOfChannels;
  unsigned long sampleRate = wavHeader->sampleRate;
  unsigned short bitsPerSample = wavHeader->bitsPerSample;

  try
  {
    /// Set output sample rate of audiodevice
    audioDeviceProxy->callVoid("setParameter",
                               std::string("outputSampleRate"),
                               (int)sampleRate);
  }
  catch(ALError &e)
  {
    throw AL::ALError("ALSoundProcessing",
                      "playWavFile()",
                      e.getDescription());
  }

  /// Go to the beginning of the audio data
  fseek(fInputWavFile, 44, SEEK_SET);

  /// Reading of the audio data
  /// Buffer to store the data contained in the wav file
  short * fInputAudioData = new short[outputBufferSize*nbOfChannels];
  /// Buffer to construct stereo audio data
  short * fStereoAudioData = new short[outputBufferSize*numberOfOutputChannels];

  /// ALValue where to store the stereo audio data to send
  ALValue pDataBin;
  while(!feof(fInputWavFile))
  {
    /// Read samples from file
    int fNbOfInputSamples = fread(fInputAudioData,
                                  bitsPerSample/8*nbOfChannels,
                                  outputBufferSize,
                                  fInputWavFile);

    if(nbOfChannels ==1)
    {
      /// Construction of stereo audio data in case the input file is mono
      int i=0;
      for(int j=0 ; j<fNbOfInputSamples ; j++)
      {
        fStereoAudioData[i] = fInputAudioData[j];
        fStereoAudioData[i+1] = fInputAudioData[j];
        i += numberOfOutputChannels;
      }

      /// Transform audio data to binary samples
      pDataBin.SetBinary(fStereoAudioData,
                         fNbOfInputSamples*sizeof(short)*numberOfOutputChannels);
    }
    else if(nbOfChannels == 2)
    {
      /// Transform audio data to binary samples
      pDataBin.SetBinary(fInputAudioData,
                         fNbOfInputSamples*sizeof(short)*numberOfOutputChannels);
    }
    else
    {
      throw AL::ALError("ALSoundProcessing",
                        "playWavFile()",
                        "The wav file should contain a mono or stereo signal.");
    }

    /// Send the stereo audio data to audiodevice module
    try
    {
      audioDeviceProxy->call<bool>("sendRemoteBufferToOutput",
                                   fNbOfInputSamples,
                                   pDataBin);
    }
    catch(AL::ALError &e)
    {
      throw AL::ALError("ALSoundProcessing","playWavFile()", e.getDescription());
    }
  }
  fclose(fInputWavFile);
}

Main: main.cpp

main.cpp

/**
 * @author Vincent Meserette
 * Copyright (c) Aldebaran Robotics 2010 All Rights Reserved
*/

#ifndef _WIN32
#include <signal.h>
#endif

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

#ifdef SOUNDPLAYBACK_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);

  // create module instances
  AL::ALModule::createModule<ALSoundPlayback>(pBroker,"ALSoundPlayback");
  return 0;
}

ALCALL int _closeModule()
{
  return 0;
}

} // extern "C"


#ifdef SOUNDPLAYBACK_IS_REMOTE

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

  // call main
  ALTools::mainFunction("alsoundplayback", argc, argv, sig);
}

#endif

CMakeLists.txt

CMakeLists.txt

# Copyright (C) 2010 Aldebaran Robotics

cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR)
project(soundplayback)
include("qibuild.cmake")


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


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

if(SOUNDPLAYBACK_IS_REMOTE)
  add_definitions("-DSOUNDPLAYBACK_IS_REMOTE")
  qi_create_bin(soundplayback ${_srcs})
else()
  qi_create_lib(soundplayback SHARED ${_srcs} SUBFOLDER naoqi)
endif()

qi_use_lib(soundplayback ALCOMMON ALAUDIO)