Skip to content
Permalink
Browse files

Added wav file loader data reading. Added prototypic al ALSA sound ou…

…tput.
  • Loading branch information...
dedeibel committed Nov 2, 2008
1 parent eae9915 commit 52be8ff814a62d4cc8f77522a9719f10bce620d3
Showing with 216 additions and 22 deletions.
  1. +100 −2 AlsaOutput.cpp
  2. +9 −0 AlsaOutput.h
  3. +2 −2 Annoyme.cpp
  4. +2 −1 Makefile
  5. +9 −0 Sample.h
  6. +64 −15 SimpleWaveFileLoader.cpp
  7. +1 −1 SimpleWaveFileLoader.h
  8. +27 −1 exceptions.h
  9. +2 −0 stdheaders.h
@@ -27,10 +27,13 @@

#include <string>
#include <iostream>
#include <alsa/asoundlib.h>

using namespace std;

#include "exceptions.h"
#include "Sample.h"

#include "AlsaOutput.h"


@@ -45,14 +48,109 @@ AlsaOutput::~AlsaOutput()

}

void AlsaOutput::playSound(const Sample *sound)
void AlsaOutput::playSound(const Sample *sample)
{
std::cout << "Playing sound " << sound->getName() << std::endl;
std::cout << "Playing sound " << sample->getName() << std::endl;
int pcmreturn;
unsigned int frames = sample->getSize() >> 2;
int i = 0;
while ((pcmreturn = snd_pcm_writei(m_pcm_handle, sample->getData(), frames)) < 0) {
snd_pcm_prepare(m_pcm_handle);
fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
if (++i > 100) break;
}
}

void AlsaOutput::open()
{
/* Allocate the snd_pcm_hw_params_t structure on the stack. */
snd_pcm_hw_params_alloca(&m_hwparams);

/* Open PCM. The last parameter of this function is the mode. */
/* If this is set to 0, the standard mode is used. Possible */
/* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC. */
/* If SND_PCM_NONBLOCK is used, read / write access to the */
/* PCM device will return immediately. If SND_PCM_ASYNC is */
/* specified, SIGIO will be emitted whenever a period has */
/* been completely processed by the soundcard. */
if (snd_pcm_open(&m_pcm_handle, m_device.c_str(), m_stream, 0) < 0)
{
throw AlsaOutputException(
string("ALSA output: could not open output device: ") + m_device);
}

/* Init hwparams with full configuration space */
if (snd_pcm_hw_params_any(m_pcm_handle, m_hwparams) < 0)
{
throw AlsaOutputException("ALSA output: Can not configure this PCM device.");
}

unsigned int rate = 11025; /* Sample rate, alt. 22050, 44100 */
unsigned int exact_rate; /* Sample rate returned by */
/* snd_pcm_hw_params_set_rate_near */
//int dir; /* exact_rate == rate --> dir = 0 */
/* exact_rate < rate --> dir = -1 */
/* exact_rate > rate --> dir = 1 */
int periods = 2; /* Number of periods */
//snd_pcm_uframes_t periodsize = 8192; /* Periodsize (bytes) */
snd_pcm_uframes_t periodsize = 12220; /* Periodsize (bytes) */

/* Set access type. This can be either */
/* SND_PCM_ACCESS_RW_INTERLEAVED or */
/* SND_PCM_ACCESS_RW_NONINTERLEAVED. */
/* There are also access types for MMAPed */
/* access, but this is beyond the scope */
/* of this introduction. */
if (snd_pcm_hw_params_set_access(m_pcm_handle, m_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
{
throw AlsaOutputException("ALSA output: Error setting access.");
}

/* Set sample format */
if (snd_pcm_hw_params_set_format(m_pcm_handle, m_hwparams, SND_PCM_FORMAT_S16_LE) < 0)
{
throw AlsaOutputException("ALSA output: Error setting format.");
}

/* Set sample rate. If the exact rate is not supported */
/* by the hardware, use nearest possible rate. */
exact_rate = rate;
if (snd_pcm_hw_params_set_rate_near(m_pcm_handle, m_hwparams, &exact_rate, 0) < 0)
{
throw AlsaOutputException("ALSA output: Error setting rate.");
}

if (rate != exact_rate)
{
cerr << "Warning: The rate "<< rate <<" Hz is not supported by your hardware.\n"
"==> Using "<< exact_rate <<" Hz instead.\n";
}

/* Set number of channels */
if (snd_pcm_hw_params_set_channels(m_pcm_handle, m_hwparams, 2) < 0)
{
throw AlsaOutputException("ALSA output: Error setting channels.");
}

/* Set number of periods. Periods used to be called fragments. */
if (snd_pcm_hw_params_set_periods(m_pcm_handle, m_hwparams, periods, 0) < 0)
{
throw AlsaOutputException("ALSA output: Error setting periods.");
}

/* Set buffer size (in frames). The resulting latency is given by */
/* latency = periodsize * periods / (rate * bytes_per_frame) */
if (snd_pcm_hw_params_set_buffer_size(m_pcm_handle, m_hwparams, (periodsize * periods)>>2) < 0)
{
throw AlsaOutputException("ALSA output: Error setting buffersize.");
}

/* Apply HW parameter settings to */
/* PCM device and prepare device */
if (snd_pcm_hw_params(m_pcm_handle, m_hwparams) < 0)
{
throw AlsaOutputException("ALSA output: Error setting HW params.");
}
}

void AlsaOutput::close()
@@ -40,6 +40,15 @@ class AlsaOutput : public virtual SoundOutput
virtual void close();
private:
string m_device;

/* Handle for the PCM device */
snd_pcm_t *m_pcm_handle;
/* Playback stream */
snd_pcm_stream_t m_stream;
/* This structure contains information about */
/* the hardware and can be used to specify the */
/* configuration to be used for the PCM stream. */
snd_pcm_hw_params_t *m_hwparams;
};

#endif // ALSAOUTPUT_H
@@ -28,11 +28,11 @@
#include "stdheaders.h"

#include "Event.h"
#include "XevieInput.h"
#include "XevieInput.h" // TODO create factory, clean headers
#include "StaticConfiguration.h"
#include "Sample.h"
#include "SimpleWaveFileLoader.h"
#include "AlsaOutput.h"
#include "AlsaOutput.h" // TODO create factory

#include "Annoyme.h"

@@ -3,9 +3,10 @@ MAINFILES=Annoyme.o Event.o XevieInput.o StaticConfiguration.o AlsaOutput.o Samp
EXECUTABLES=annoyme
LDFLAGS=-lX11 -lXevie
SOURCES=$(wildcard *.cpp)
LIBS=-lasound
DEPS=$(patsubst %.o,%.d,$(MAINFILES))

CXXFLAGS=-Wall -I. -ggdb
CXXFLAGS=-Wall -I. -ggdb $(LIBS)

all: annoyme

@@ -152,6 +152,15 @@ class Sample
return m_type;
}

void setSize(unsigned int new_var)
{
m_size = new_var;
}

unsigned int getSize() const
{
return m_size;
}

private:
SampleFormat m_format;
@@ -25,8 +25,11 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "stdheaders.h"
#include "stdheaders.h" // TODO cleanup headers
#include <glob.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "exceptions.h"
#include "Sample.h"
@@ -118,22 +121,68 @@ void SimpleWaveFileLoader::getSample(enum Sample::SampleType type, const Sample

void SimpleWaveFileLoader::loadSampleFromFile(const char *path)
{
const string name(this->getName(path));
const enum Sample::SampleType type = Sample::getSampleType(name);
if (type != Sample::invalidType)
{
Sample *sample = new Sample();
sample->setName(name);
sample->setFilePath(path);
sample->setType(Sample::getSampleType(name));
samples.insert(make_pair(sample->getType(), sample));
}
else {
cout << "Invalid sample: " << name << endl;
}
const string name(this->getName(path));
const enum Sample::SampleType type = Sample::getSampleType(name);
if (type == Sample::invalidType)
{
cerr << "Invalid sample: " << name << endl;
return;
}

Sample *sample = new Sample();

try
{
sample->setName(name);
sample->setFilePath(path);
sample->setType(type);

loadDataFromFile(sample);
}
catch (...)
{
delete sample;
throw;
}

samples.insert(make_pair(sample->getType(), sample));
}

void loadDataFromFile(const char *path, char *&data, unsigned int &size)
void SimpleWaveFileLoader::loadDataFromFile(Sample *sample)
{
sample->setFormat(Sample::PCM);
sample->setRate(11025);

unsigned int size = 0;
char* data = 0;

unsigned int allocated = 32000 * sizeof(char);
unsigned int bytesRead = 0;

int file = open(sample->getFilePath().c_str(), O_RDONLY);
if (file == 0) return;

data = (char*)malloc(allocated);
// TODO add error messages
while ((bytesRead = read(file, data, allocated - size)))
{
size += bytesRead;
if (size >= allocated) {
allocated *= 2;
data = (char*)realloc(data, allocated);
}
if (data == 0)
{
cerr << "allocation of more memory to read sample file '"
<< sample->getFilePath() << "' failed.\n";
break;
}
}

sample->setSize(size);
sample->setData(data);
cout << " read sample '" << sample->getName() << "' with "
<< sample->getSize() << " Bytes.\n";

close(file);
}
@@ -42,7 +42,7 @@ class SimpleWaveFileLoader : virtual public SoundLoader
private:
void insertDefault();
void loadSampleFromFile(const char *path);
void loadDataFromFile(const char *path, char *&data, unsigned int &size);
void loadDataFromFile(Sample *sample);

inline const string getName(const char *path)
{
@@ -96,7 +96,7 @@ class AnnoyErrnoException : public AnnoymeException
{
public:

AnnoyErrnoException(string msg, string subject, int errnum) throw()
AnnoyErrnoException(string msg, const string &subject, int errnum) throw()
: errnum(errnum)
{
msg += ": ";
@@ -112,3 +112,29 @@ class AnnoyErrnoException : public AnnoymeException

int errnum;
};

class SoundOutputException : public AnnoymeException
{
public:

SoundOutputException(const string &msg) throw()
: AnnoymeException(msg)
{

}

virtual ~SoundOutputException() throw() {};
};

class AlsaOutputException : public SoundOutputException
{
public:

AlsaOutputException(const string &msg) throw()
: SoundOutputException(msg)
{

}

virtual ~AlsaOutputException() throw() {};
};
@@ -18,4 +18,6 @@
#include <sys/types.h>
#include <sys/stat.h>

#include <alsa/asoundlib.h>

using namespace std;

0 comments on commit 52be8ff

Please sign in to comment.
You can’t perform that action at this time.