proteaAudio/proAudio.cpp
2012-05-27 18:34:36 -04:00

168 lines
5.6 KiB
C++

#include "proAudio.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
using namespace std;
//--- class AudioSample --------------------------------------------
AudioSample::AudioSample(const AudioSample & source) :
m_size(source.m_size), m_channels(source.m_channels), m_sampleRate(source.m_sampleRate), m_bitsPerSample(source.m_bitsPerSample) {
m_data = new unsigned char [m_size]; memcpy(m_data,source.m_data, m_size);
}
bool AudioSample::bitsPerSample(unsigned short bits) {
if(bits==16) {
if(m_bitsPerSample==8) {
unsigned char* data = new unsigned char[2*m_size];
for(unsigned int i=0; i<m_size; ++i) {
signed short *ptr =(signed short*)data+i;
*ptr = m_data[i]*255;
}
delete [] m_data;
m_data = data;
m_size*=2;
return true;
}
else if(m_bitsPerSample==16) {
return true; // nothing to do
}
else if(m_bitsPerSample==32) { // float, normalized from -1.0f to 1.0f
unsigned char* data = new unsigned char[m_size/2];
for(unsigned int i=0; i<m_size/4; ++i) {
signed short *ptr =(signed short*)data+i;
float* src=(float*)m_data+i;
*ptr =(signed short)(*src*SHRT_MAX);
}
delete [] m_data;
m_data = data;
m_size/=2;
return true;
}
}
fprintf(stderr,"AudioSample::bitsPerSample ERROR: conversion from %i to %i bits not supported.\n", m_bitsPerSample, bits);
return false;
}
void AudioSample::volume(float f) {
if(m_bitsPerSample==8) for(signed char *ptr =(signed char *)m_data; ptr<(signed char *)m_data+m_size; ++ptr) {
float value=*ptr * f;
if(value>CHAR_MAX) *ptr =CHAR_MAX;
else if(value<CHAR_MIN) *ptr =CHAR_MIN;
else *ptr =(signed char)value;
}
else if(m_bitsPerSample==16) for(signed short *ptr =(signed short*)m_data; ptr<(signed short*)m_data+m_size/2; ++ptr) {
float value=*ptr * f;
if(value>SHRT_MAX) *ptr =SHRT_MAX;
else if(value<SHRT_MIN) *ptr =SHRT_MIN;
else *ptr =(signed short)value;
}
else if(m_bitsPerSample==32) for(float *ptr =(float*)m_data; ptr<(float*)m_data+m_size/4; ++ptr) {
*ptr *= f;
if(*ptr>1.0f) *ptr=1.0f;
else if(*ptr<-1.0f) *ptr=-1.0f;
}
else fprintf(stderr,"AudioSample::changeVolume ERROR: %i bits per sample not supported.\n",m_bitsPerSample);
}
AudioSample* AudioSample::readWav(FILE* stream, size_t (*readFunc)( void *, size_t, size_t, FILE *)) {
char id[4]; //four unsigned chars to hold chunk IDs
readFunc(id,sizeof(unsigned char),4,stream);
if (strncmp(id,"RIFF",4)!=0) return 0;
unsigned int size;
readFunc(&size,sizeof(unsigned int),1,stream);
readFunc(id,sizeof(unsigned char),4,stream);
if (strncmp(id,"WAVE",4)!=0) return 0;
unsigned short encoding, block_align, channels, bitsPerSample;
unsigned int chunk_length, byte_rate, sampleRate;
readFunc(id, sizeof(unsigned char), 4, stream); //read ID 'fmt ';
readFunc(&chunk_length, sizeof(unsigned int),1,stream); // header length, 16 expected
readFunc(&encoding, sizeof(short), 1, stream); // should be "1" for simple PCM data
if(encoding!=1) return 0;
readFunc(&channels, sizeof(short),1,stream);
readFunc(&sampleRate, sizeof(unsigned int), 1, stream);
readFunc(&byte_rate, sizeof(unsigned int), 1, stream);
readFunc(&block_align, sizeof(short), 1, stream);
readFunc(&bitsPerSample, sizeof(short), 1, stream);
readFunc(id, sizeof(unsigned char), 4, stream); // read ID 'data'
readFunc(&size, sizeof(unsigned int), 1, stream);
unsigned char *data = new unsigned char[size];
readFunc(data, sizeof(unsigned char), size, stream);
return new AudioSample(data,size, channels, sampleRate, bitsPerSample);
}
AudioSample* AudioSample::loadWav(const std::string & fname) {
#ifdef _MSC_VER
FILE *fp = 0;
fopen_s(&fp, fname.c_str(), "rb");
#else
FILE *fp = fopen(fname.c_str(), "rb");
#endif
if (!fp) return 0;
AudioSample * pSample = readWav(fp, fread);
fclose(fp);
return pSample;
}
//--- class DeviceAudio --------------------------------------------
DeviceAudio* DeviceAudio::s_instance=0;
extern "C" {
extern int stb_vorbis_decode_filename(char *filename, int *channels, int* sample_rate, short **output);
};
static AudioSample* loadOgg(const std::string & fname) {
int channels, sampleRate;
short *decoded;
int len = stb_vorbis_decode_filename(const_cast<char*>(fname.c_str()), &channels, &sampleRate, &decoded);
if(len<0) return 0;
// convert to AudioSample:
unsigned int size = len*channels*sizeof(short);
unsigned char * data = new unsigned char[size];
if(!data) return 0;
memcpy(data,decoded, size);
free(decoded);
return new AudioSample(data, size, channels, sampleRate, 16);
}
static string toLower(const string & s) {
string retStr(s);
for(size_t i=0; i<s.size(); ++i)
retStr[i]=static_cast<char>(tolower(retStr[i]));
return retStr;
}
DeviceAudio::DeviceAudio() : m_freqOut(0), m_volL(1.0f), m_volR(1.0f) {
loaderRegister(AudioSample::loadWav,"wav");
loaderRegister(loadOgg,"ogg");
}
unsigned int DeviceAudio::sampleFromFile(const std::string & filename, float volume) {
if(filename.rfind('.')>filename.size()) return 0;
string suffix=toLower(filename.substr(filename.rfind('.')+1));
map<string, AudioSample * (*)(const string &)>::iterator it = mm_loader.find(suffix);
if(it==mm_loader.end()) return 0;
AudioSample* pSample = (*(it->second))(filename);
if(!pSample) return 0;
unsigned int ret = sampleFromMemory(*pSample, volume);
delete pSample;
return ret;
}
bool DeviceAudio::loaderRegister(AudioSample *(*loadFunc)(const std::string &), const std::string & suffix) {
return mm_loader.insert(std::make_pair(toLower(suffix),loadFunc)).second;
}
bool DeviceAudio::loaderAvailable(const std::string & suffix) const {
return mm_loader.find(toLower(suffix))!=mm_loader.end();
}