#include "proAudio.h" #include #include #include #include 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; iCHAR_MAX) *ptr =CHAR_MAX; else if(valueSHRT_MAX) *ptr =SHRT_MAX; else if(value1.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(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(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::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(); }