Skip to content

Instantly share code, notes, and snippets.

@misugijunz
Created September 28, 2012 04:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save misugijunz/fe1fcbbb6753bb7ff06b to your computer and use it in GitHub Desktop.
Save misugijunz/fe1fcbbb6753bb7ff06b to your computer and use it in GitHub Desktop.
source code
//main.cpp file
#include "audio.h"
#include <QApplication>
#include <QtCore/QCoreApplication>
#include <QDeclarativeView>
#include <QDeclarativeContext>
#include <QtDebug>
#include <QFile>
#include <QTextStream>
//#include <AL/alut.h>
void msgHandler( QtMsgType type, const char* msg )
{
const char symbols[] = { 'I', 'E', '!', 'X' };
QString output = QString("[%1] %2").arg( symbols[type] ).arg( msg );
//std::cerr << output.toStdString() << std::endl;
QFile outFile("debuglog.txt");
outFile.open(QIODevice::WriteOnly | QIODevice::Append);
QTextStream ts(&outFile);
ts << output << endl;
if( type == QtFatalMsg ) abort();
}
int main(int argc, char *argv[])
{
//qInstallMsgHandler( msgHandler );
QApplication a(argc, argv);
Audio audioPlayer;
QDeclarativeView view;
qDebug() << "HPRE";
/*if (!alutInit(0, 0)) {
//fprintf(stderr, "Could not start sound: %d\n", alutGetError());
return EXIT_FAILURE;
}*/
// give audio player to game engine
view.rootContext()->setContextProperty("audioPlayer", &audioPlayer);
#ifdef Q_OS_QNX
view.setSource(QUrl("app/native/qml/rod/main.qml"));
#else
view.setSource(QUrl("qml/rod/main.qml"));
#endif
#if defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5)
m_SystemDeviceInfo = new QSystemDeviceInfo(this);
//audioPlayer.init(m_SystemDeviceInfo);
#else
// audioPlayer.init();
#endif
// speed up from symbian ^3
view.setAttribute(Qt::WA_NoSystemBackground);
view.setAttribute(Qt::WA_AutoOrientation, true);
view.setResizeMode(QDeclarativeView::SizeRootObjectToView);
view.showMaximized();
//alutExit();
return a.exec();
}
//audio.h file
#ifndef AUDIO_H
#define AUDIO_H
#include <QObject>
#include "soundmanager.h"
class Audio : public QObject
{
Q_OBJECT
public:
explicit Audio(QObject *parent = 0);
~Audio();
/**
* Invokable function used for triggering sounds from QML.
*
* @param msg a string describing which sound should be played.
*/
Q_INVOKABLE
void playSound(int index);
Q_INVOKABLE
void setEnable(bool mode);
private:
bool m_Mute;
bool m_SilentProfile;
SoundManager *mSoundManager;
};
#endif // AUDIO_H
//audio.cpp
#include "audio.h"
#include <stdio.h>
#include <qdebug.h>
Audio::Audio(QObject *parent) :
QObject(parent)
{
mSoundManager = new SoundManager("sounds/");
}
Audio::~Audio()
{
// Destroy the sound manager.
delete mSoundManager;
}
void Audio::playSound(int index)
{
//if(m_Mute) return;
//if(m_SilentProfile) return;
printf("playSound(%d)\n", index);
qDebug() << "playSound" << index;
switch(index) {
case 0:
// menu select
mSoundManager->play("50561__broumbroum__sf3_sfx_menu_select.wav");
break;
case 1:
// drop item
mSoundManager->play("118401__numar__7_Thump.wav");
break;
case 2:
// wrong box
mSoundManager->play("54047__guitarguy1985__buzzer.wav");
break;
default:
return;
}
}
void Audio::setEnable(bool mode)
{
m_Mute = !mode;
/*if(m_Mute){
stopSound();
}*/
}
//SoundManager.h
/* Copyright (c) 2012 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SOUNDMANAGER_H
#define _SOUNDMANAGER_H
#include <AL/al.h>
#include <AL/alc.h>
#include <AL/alut.h>
#include <QtCore/qstring.h>
#include <qhash.h>
#include <stdio.h>
// The number of max number of sound sources.
#define SOUNDMANAGER_MAX_NBR_OF_SOURCES 32
/**
* SoundManager
*
* A very basic sound manager class for playing sounds using OpenAL.
*/
class SoundManager
{
public:
/**
* Constructor, initializes the sound manager. This function sets up OpenAL
* and loads all sounds from the specified directory. This directory should
* be a folder only containing valid sounds.
*
* @param soundDirectory directory where all sounds are kept (have to be located in the assets/ folder)
*/
SoundManager(QString soundDirectory);
/**
* Destructor destroys all buffers and sources.
*/
~SoundManager();
/**
* Called by the constructor, loads all sounds from the specified directory.
*
* @param soundDirectory directory where all sounds are kept (have to be located in the assets/ folder)
*/
bool init(QString soundDirectory);
/**
* Plays a sound.
*
* @param fileName the name of the file in the soundDirectory.
*/
bool play(QString fileName);
/**
* Plays a sound, with modified pitch and gain.
*
* @param fileName the name of the file in the soundDirectory
* @param pitch specifies the pitch to be applied to a sound Range: [0.5-2.0]
* @param gain sound gain (volume amplification) Range: ]0.0- ]
*/
bool play(QString fileName, float pitch, float gain);
private:
// Load the .wav files
bool loadWav(FILE* file, ALuint buffer);
// Sound buffers.
QHash<QString, ALuint> mSoundBuffers;
// Sound sources.
ALuint mSoundSources[SOUNDMANAGER_MAX_NBR_OF_SOURCES];
};
#endif //_SOUNDMANAGER_H
//soundmanager.cpp file
/* Copyright (c) 2012 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "soundmanager.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <QDir>
#include <qdebug.h>
// Error message function for ALUT.
static void reportALUTError(ALenum error)
{
if (error != ALUT_ERROR_NO_ERROR)
qDebug() << "ALUT reported the following error: " << alutGetErrorString(error);
}
// Error message function for OpenAL.
static void reportOpenALError(ALenum error)
{
if (error != AL_NO_ERROR)
qDebug() << "OpenAL reported the following error: \n" << alutGetErrorString(error);
}
SoundManager::SoundManager(QString soundDirectory)
{
QString applicationDirectory;
QString completeSoundDirectory;
char cwd[PATH_MAX];
// Initialize ALUT.
if (alutInit(NULL, NULL) == false) {
reportALUTError(alutGetError());
}
// Get the complete application directory in which we will load sounds from.
// We convert to QString since it is more convenient when working with directories.
getcwd(cwd, PATH_MAX);
applicationDirectory = QString(cwd);
// Append the assets directory and the actual sounds directory name.
completeSoundDirectory = applicationDirectory
.append("/app/native/qml/rod/")
.append(soundDirectory);
printf("%s\n", completeSoundDirectory.toAscii().constData());
// Create OpenAL buffers from all files in the sound directory.
QDir dir(completeSoundDirectory);
if (!dir.exists()) {
qDebug() << "Cannot find the sounds directory." << completeSoundDirectory;
printf("Cannot find the sounds directory %s.\n", completeSoundDirectory.toAscii().constData());
} else {
// Set a filter for file listing, only files should be listed.
dir.setFilter(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot);
// Get a directory listing.
QFileInfoList list = dir.entryInfoList();
// Traverse and load all the audio files into buffers.
for (int i = 0; i < list.size(); ++i) {
// Create a file info for each audio file.
QFileInfo fileInfo = list.at(i);
const char* path = fileInfo.absoluteFilePath().toStdString().c_str();
ALenum error;
// Generate buffers to hold audio data.
alGenBuffers(1, &mSoundBuffers[fileInfo.fileName()]);
error = alGetError();
if (error != AL_NO_ERROR) {
reportOpenALError(error);
break;
}
// Load sound file.
FILE* file = fopen(path, "rb");
if (!file) {
qDebug() << "Failed to load audio file " << path;
printf("Failed to load audio file %s\n", path);
break;
}
// Read the file header
char header[12];
ALuint bufferId = mSoundBuffers[fileInfo.fileName()];
if (fread(header, 1, 12, file) != 12) {
qDebug() << "Invalid header for audio file " << path;
printf("Invalid header for audio file %s\n", path);
alDeleteBuffers(1, &bufferId);
goto cleanup;
}
// Check the file format & load the buffer with audio data.
if (memcmp(header, "RIFF", 4) == 0) {
if (!loadWav(file, bufferId)) {
qDebug() << "Invalid wav file: " << path;
printf("Invalid wav file %s\n", path);
alDeleteBuffers(1, &bufferId);
goto cleanup;
}
}
/*else if (memcmp(header, "OggS", 4) == 0) {
if (!loadOgg(file, bufferId)) {
qDebug() << "Invalid ogg file: " << path;
alDeleteBuffers(1, &bufferId);
goto cleanup;
}
}*/
else {
qDebug() << "Unsupported audio file: " << path;
printf("Unsupported audio file %s\n", path);
goto cleanup;
}
cleanup:
if (file) {
fclose(file);
}
}
}
// Generate a number of sources used to attach buffers and play.
alGenSources(SOUNDMANAGER_MAX_NBR_OF_SOURCES, mSoundSources);
ALenum error = alGetError();
if (error != AL_NO_ERROR) {
reportOpenALError(error);
}
}
SoundManager::~SoundManager()
{
ALuint bufferID = 0;
// Clear all the sources.
for (int sourceIndex = 0; sourceIndex < SOUNDMANAGER_MAX_NBR_OF_SOURCES; sourceIndex++) {
ALuint source = mSoundSources[sourceIndex];
alDeleteSources(1, &source);
ALenum error = alGetError();
if (error != AL_NO_ERROR) {
reportOpenALError(error);
}
}
// Clear buffers, iterate through the hash
QHashIterator<QString, ALuint> iterator(mSoundBuffers);
while (iterator.hasNext()) {
iterator.next();
// Get the buffer id and delete it.
bufferID = mSoundBuffers[iterator.key()];
if(bufferID != 0) {
alDeleteBuffers(1, &bufferID);
ALenum error = alGetError();
if (error != AL_NO_ERROR) {
reportOpenALError(error);
}
}
}
// Clear the QHash for sound buffer id's.
mSoundBuffers.clear();
// Exit ALUT.
ALenum error = alGetError();
if (error != AL_NO_ERROR) {
reportALUTError(error);
}
}
bool SoundManager::loadWav(FILE* file, ALuint buffer)
{
unsigned char stream[12];
// Verify the wave fmt magic value meaning format.
if (fread(stream, 1, 8, file) != 8 || memcmp(stream, "fmt ", 4) != 0 ) {
qDebug() << "Failed to verify the magic value for the wave file format.";
printf("Failed to verify the magic value for the wave file format.\n");
return false;
}
unsigned int section_size;
section_size = stream[7]<<24;
section_size |= stream[6]<<16;
section_size |= stream[5]<<8;
section_size |= stream[4];
// Check for a valid pcm format.
if (fread(stream, 1, 2, file) != 2 || stream[1] != 0 || stream[0] != 1) {
qDebug() << "Unsupported audio file format (must be a valid PCM format).";
printf("Unsupported audio file format (must be a valid PCM format).\n");
return false;
}
// Get the channel count (16-bit little-endian).
int channels;
if (fread(stream, 1, 2, file) != 2) {
qDebug() << "Failed to read the wave file's channel count.";
printf("Failed to read the wave file's channel count.\n");
return false;
}
channels = stream[1]<<8;
channels |= stream[0];
// Get the sample frequency (32-bit little-endian).
ALuint frequency;
if (fread(stream, 1, 4, file) != 4) {
qDebug() << "Failed to read the wave file's sample frequency.";
printf("Failed to read the wave file's sample frequency.\n");
return false;
}
frequency = stream[3]<<24;
frequency |= stream[2]<<16;
frequency |= stream[1]<<8;
frequency |= stream[0];
// The next 6 bytes hold the block size and bytes-per-second.
// We don't need that info, so just read and ignore it.
// We could use this later if we need to know the duration.
if (fread(stream, 1, 6, file) != 6) {
qDebug() << "Failed to read past the wave file's block size and bytes-per-second.";
printf("Failed to read past the wave file's block size and bytes-per-second.\n");
return false;
}
// Get the bit depth (16-bit little-endian).
int bits;
if (fread(stream, 1, 2, file) != 2) {
qDebug() << "Failed to read the wave file's bit depth.";
printf("Failed to read the wave file's bit depth.\n");
return false;
}
bits = stream[1]<<8;
bits |= stream[0];
// Now convert the given channel count and bit depth into an OpenAL format.
ALuint format = 0;
if (bits == 8) {
if (channels == 1)
format = AL_FORMAT_MONO8;
else if (channels == 2)
format = AL_FORMAT_STEREO8;
}
else if (bits == 16) {
if (channels == 1)
format = AL_FORMAT_MONO16;
else if (channels == 2)
format = AL_FORMAT_STEREO16;
}
else {
qDebug() << "Incompatible wave file format: ( " << channels << ", " << bits << ")";
return false;
}
// Check against the size of the format header as there may be more data that we need to read.
if (section_size > 16) {
unsigned int length = section_size - 16;
// Extension size is 2 bytes.
if (fread(stream, 1, length, file) != length) {
qDebug() << "Failed to read extension size from wave file.";
return false;
}
}
// Read in the rest of the file a chunk (section) at a time.
while (true) {
// Check if we are at the end of the file without reading the data.
if (feof(file)) {
qDebug() << "Failed to load wave file; file appears to have no data.";
return false;
}
// Read in the type of the next section of the file.
if (fread(stream, 1, 4, file) != 4) {
qDebug() << "Failed to read next section type from wave file.";
return false;
}
// Data chunk.
if (memcmp(stream, "data", 4) == 0) {
// Read how much data is remaining and buffer it up.
unsigned int dataSize;
if (fread(&dataSize, sizeof(int), 1, file) != 1) {
qDebug() << "Failed to read size of data section from wave file.";
return false;
}
char* data = new char[dataSize];
if (fread(data, sizeof(char), dataSize, file) != dataSize) {
qDebug() << "Failed to load wave file; file is missing data.";
delete data;
return false;
}
alBufferData(buffer, format, data, dataSize, frequency);
ALenum error = alGetError();
if (error != AL_NO_ERROR) {
reportOpenALError(error);
}
delete data;
// We've read the data, so return now.
return true;
}
// Other chunk - could be any of the following:
// - Fact ("fact")
// - Wave List ("wavl")
// - Silent ("slnt")
// - Cue ("cue ")
// - Playlist ("plst")
// - Associated Data List ("list")
// - Label ("labl")
// - Note ("note")
// - Labeled Text ("ltxt")
// - Sampler ("smpl")
// - Instrument ("inst")
else {
// Store the name of the chunk so we can report errors informatively.
char chunk[5] = { 0 };
memcpy(chunk, stream, 4);
// Read the chunk size.
if (fread(stream, 1, 4, file) != 4) {
qDebug() << "Failed to read size of " << chunk << "chunk from wave file.";
return false;
}
section_size = stream[3]<<24;
section_size |= stream[2]<<16;
section_size |= stream[1]<<8;
section_size |= stream[0];
// Seek past the chunk.
if (fseek(file, section_size, SEEK_CUR) != 0) {
qDebug() << "Failed to seek past " << chunk << "in wave file.";
return false;
}
}
}
return true;
}
/*bool SoundManager::loadOgg(FILE* file, ALuint buffer)
{
OggVorbis_File ogg_file;
vorbis_info* info;
ALenum format;
int result;
int section;
unsigned int size = 0;
rewind(file);
if ((result = ov_open(file, &ogg_file, NULL, 0)) < 0) {
fclose(file);
qDebug() << "Failed to open ogg file.";
return false;
}
info = ov_info(&ogg_file, -1);
if (info->channels == 1)
format = AL_FORMAT_MONO16;
else
format = AL_FORMAT_STEREO16;
// size = #samples * #channels * 2 (for 16 bit).
unsigned int data_size = ov_pcm_total(&ogg_file, -1) * info->channels * 2;
char* data = new char[data_size];
while (size < data_size) {
result = ov_read(&ogg_file, data + size, data_size - size, 0, 2, 1, &section);
if (result > 0) {
size += result;
}
else if (result < 0) {
delete data;
qDebug() << "Failed to read ogg file; file is missing data.";
return false;
}
else {
break;
}
}
if (size == 0) {
delete data;
qDebug() << "Filed to read ogg file; unable to read any data.";
return false;
}
alBufferData(buffer, format, data, data_size, info->rate);
ALenum error = alGetError();
if (error != AL_NO_ERROR) {
reportOpenALError(error);
}
delete data;
ov_clear(&ogg_file);
// ov_clear actually closes the file pointer as well.
file = 0;
return true;
}*/
bool SoundManager::play(QString fileName, float pitch, float gain)
{
static uint sourceIndex = 0;
qDebug() << "Playing " << fileName;
// Get the corresponding buffer id set up in the init function.
ALuint bufferID = mSoundBuffers[fileName];
if (bufferID != 0) {
// Increment which source we are using, so that we play in a "free" source.
sourceIndex = (sourceIndex + 1) % SOUNDMANAGER_MAX_NBR_OF_SOURCES;
// Get the source in which the sound will be played.
ALuint source = mSoundSources[sourceIndex];
if (alIsSource (source) == AL_TRUE) {
// Attach the buffer to an available source.
alSourcei(source, AL_BUFFER, bufferID);
ALenum error = alGetError();
if (error != AL_NO_ERROR) {
reportOpenALError(error);
}
// Set the source pitch value.
alSourcef(source, AL_PITCH, pitch);
error = alGetError();
if (error != AL_NO_ERROR) {
reportOpenALError(error);
}
// Set the source gain value.
alSourcef(source, AL_GAIN, gain);
error = alGetError();
if (error != AL_NO_ERROR) {
reportOpenALError(error);
}
// Play the source.
printf("Play the source\n");
alSourcePlay(source);
error = alGetError();
if (error != AL_NO_ERROR) {
reportOpenALError(error);
}
}
} else {
// The buffer was not found.
printf("The buffer was not found\n");
return false;
}
return true;
}
bool SoundManager::play(QString fileName)
{
// Play the sound with default gain and pitch values.
return play(fileName, 4.0f, 4.0f);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment