diff options
Diffstat (limited to 'orkbasecxx/audiofile')
-rw-r--r-- | orkbasecxx/audiofile/AudioFile.cpp | 63 | ||||
-rw-r--r-- | orkbasecxx/audiofile/AudioFile.h | 71 | ||||
-rw-r--r-- | orkbasecxx/audiofile/LibSndFileFile.cpp | 138 | ||||
-rw-r--r-- | orkbasecxx/audiofile/LibSndFileFile.h | 46 | ||||
-rw-r--r-- | orkbasecxx/audiofile/Makefile.am | 6 | ||||
-rw-r--r-- | orkbasecxx/audiofile/MediaChunkFile.cpp | 154 | ||||
-rw-r--r-- | orkbasecxx/audiofile/MediaChunkFile.h | 40 | ||||
-rw-r--r-- | orkbasecxx/audiofile/PcmFile.cpp | 117 | ||||
-rw-r--r-- | orkbasecxx/audiofile/PcmFile.h | 41 |
9 files changed, 676 insertions, 0 deletions
diff --git a/orkbasecxx/audiofile/AudioFile.cpp b/orkbasecxx/audiofile/AudioFile.cpp new file mode 100644 index 0000000..848f55b --- /dev/null +++ b/orkbasecxx/audiofile/AudioFile.cpp @@ -0,0 +1,63 @@ +/* + * Oreka -- A media capture and retrieval platform + * + * Copyright (C) 2005, orecx LLC + * + * http://www.orecx.com + * + * This program is free software, distributed under the terms of + * the GNU General Public License. + * Please refer to http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "AudioFile.h" +#include "ace/OS_NS_unistd.h" + +void AudioFile::Open(fileOpenModeEnum mode, bool stereo , int sampleRate) +{ + Open(m_filename, mode, stereo, sampleRate); +} + + +void AudioFile::RecursiveMkdir(CStdString& path) +{ + int position = 0; + bool done = false; + while (!done) + { + position = path.Find('/', position+1); + if (position == -1) + { + done = true; + } + else + { + CStdString level = path.Left(position); + ACE_OS::mkdir((PCSTR)level); + } + } +} + +void AudioFile::MoveOrig() +{ + CStdString newName = m_filename + ".orig"; + if (ACE_OS::rename((PCSTR)m_filename, (PCSTR)newName) == 0) + { + m_filename = newName; + } + else + { + throw(CStdString("AudioFile::MoveOrig: could not rename file:" + m_filename)); + } +} + +void AudioFile::Delete() +{ + ACE_OS::unlink((PCSTR)m_filename); +} + +int AudioFile::GetSampleRate() +{ + return m_sampleRate; +}
\ No newline at end of file diff --git a/orkbasecxx/audiofile/AudioFile.h b/orkbasecxx/audiofile/AudioFile.h new file mode 100644 index 0000000..bc9cbcf --- /dev/null +++ b/orkbasecxx/audiofile/AudioFile.h @@ -0,0 +1,71 @@ +/* + * Oreka -- A media capture and retrieval platform + * + * Copyright (C) 2005, orecx LLC + * + * http://www.orecx.com + * + * This program is free software, distributed under the terms of + * the GNU General Public License. + * Please refer to http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef __AUDIOFILE_H__ +#define __AUDIOFILE_H__ + +#include "boost/shared_ptr.hpp" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_sys_stat.h" + +#include "StdString.h" +#include "AudioCapture.h" + + +/** Base class for all file accessor classes. */ +class AudioFile +{ +public: + typedef enum {READ = 0, WRITE = 1} fileOpenModeEnum; + + /** Open audio file for reading or writing. + Filename should include path information but not extension (which is automatically appended) + If the underlying format does not support stereo, data is transparently read from two files in read mode + or two files are transparently written to in write mode */ + virtual void Open(CStdString& filename, fileOpenModeEnum mode, bool stereo = false, int sampleRate = 8000) = 0; + /** Same as above but uses the intenal filename */ + void Open(fileOpenModeEnum mode, bool stereo = false, int sampleRate = 8000); + /** Explicitely close the underlying file(s). This is also done automatically by the destructor */ + virtual void Close() = 0; + + /** Writes a chunk of audio to disk. + If stereo capture, this represents the local party */ + virtual void WriteChunk(AudioChunkRef chunkRef) = 0; + /** Writes a chunk of audio from the remote pary to disk (if stereo capture) + //virtual bool WriteRemoteChunk(AudioChunkRef chunkRef) = 0; + /** Reads a chunk of audio stereo-wise + If underlying storage is mono, remoteChunk will be NULL + ReadChunkStereo guarantees that local and remote chunks returned are in sync */ + //virtual bool ReadChunkStereo(AudioChunkRef& chunk, AudioChunkRef& remoteChunk) = 0; + /** Reads a chunk of audio mono-wise + If underlying file is stereo, ReadChunkMono merges the two streams in a synchronized manner and returns the result */ + virtual int ReadChunkMono(AudioChunkRef& chunk) = 0; + + /** Move the file to a new name including ".orig" suffix */ + void MoveOrig(); + void Delete(); + virtual CStdString GetExtension() = 0; + virtual int GetSampleRate(); + + static void RecursiveMkdir(CStdString& path); +protected: + CStdString m_filename; + fileOpenModeEnum m_mode; + int m_numChunksWritten; + int m_sampleRate; +}; + +typedef boost::shared_ptr<AudioFile> AudioFileRef; + +#endif + diff --git a/orkbasecxx/audiofile/LibSndFileFile.cpp b/orkbasecxx/audiofile/LibSndFileFile.cpp new file mode 100644 index 0000000..0589466 --- /dev/null +++ b/orkbasecxx/audiofile/LibSndFileFile.cpp @@ -0,0 +1,138 @@ +/* + * Oreka -- A media capture and retrieval platform + * + * Copyright (C) 2005, orecx LLC + * + * http://www.orecx.com + * + * This program is free software, distributed under the terms of + * the GNU General Public License. + * Please refer to http://www.gnu.org/copyleft/gpl.html + * + */ + +#define _WINSOCKAPI_ // prevents the inclusion of winsock.h + +#include "Utils.h" +#include "LibSndFileFile.h" + +LibSndFileFile::LibSndFileFile(int fileFormat) +{ + m_fileInfo.format = fileFormat; + m_fileInfo.frames = 0; + m_fileInfo.samplerate = 0; + m_fileInfo.channels = 0; + m_fileInfo.sections = 0; + m_fileInfo.seekable = 0; + m_pFile = NULL; + m_numChunksWritten = 0; + m_mode = READ; + m_sampleRate = 0; +} + +LibSndFileFile::~LibSndFileFile() +{ + Close(); +} + +void LibSndFileFile::Open(CStdString& filename, fileOpenModeEnum mode, bool stereo, int sampleRate) +{ + if(!m_filename.Equals(filename)) + { + m_filename = filename + ".wav"; + } + m_mode = mode; + stereo ? m_fileInfo.channels = 2 : m_fileInfo.channels = 1; + if(m_sampleRate == 0) + { + m_sampleRate = sampleRate; + m_fileInfo.samplerate = sampleRate; + } + + if( (mode==WRITE) && !sf_format_check(&m_fileInfo)) + { + throw(CStdString("libsndfile: Selected output format not supported")); + } + + RecursiveMkdir(m_filename); + + int sndFileMode; + mode == READ ? sndFileMode = SFM_READ : sndFileMode = SFM_WRITE; + m_pFile = sf_open((PCSTR)m_filename, sndFileMode, &m_fileInfo); + + if(!m_pFile) + { + throw(CStdString("sf_open failed, audio file could not be created:"+ m_filename)); + } +} + +void LibSndFileFile::WriteChunk(AudioChunkRef chunkRef) +{ + if(chunkRef.get() == NULL) + { + return; + } + if(chunkRef->GetDetails()->m_numBytes == 0) + { + return; + } + + if (m_pFile) + { + if( chunkRef->GetEncoding() == AlawAudio || chunkRef->GetEncoding() == UlawAudio) + { + if(sf_write_raw(m_pFile, chunkRef->m_pBuffer, chunkRef->GetNumSamples()) != chunkRef->GetNumSamples()) + { + CStdString numChunksWrittenString = IntToString(m_numChunksWritten); + throw(CStdString("sf_write_raw failed, audio file " + m_filename + " could not be written after " + numChunksWrittenString + " chunks written")); + } + } + else if (chunkRef->GetEncoding() == PcmAudio) + { + if(sf_write_short(m_pFile, (short*)chunkRef->m_pBuffer, chunkRef->GetNumSamples()) != chunkRef->GetNumSamples()) + { + CStdString numChunksWrittenString = IntToString(m_numChunksWritten); + throw(CStdString("sf_write_short failed, audio file " + m_filename + " could not be written after " + numChunksWrittenString + " chunks written")); + } + } + m_numChunksWritten++; + } + else + { + throw(CStdString("Write attempt on unopened file:")+ m_filename); + } +} + +int LibSndFileFile::ReadChunkMono(AudioChunkRef& chunk) +{ + unsigned int numRead = 0; + if (m_pFile) + { + chunk.reset(new AudioChunk()); + short temp[8000]; + numRead = sf_read_short(m_pFile, temp, 8000); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + chunk->SetBuffer(temp, sizeof(short)*numRead, details); + } + else + { + throw(CStdString("Read attempt on unopened file:")+ m_filename); + } + return numRead; +} + + +void LibSndFileFile::Close() +{ + if (m_pFile) + { + sf_close(m_pFile); + m_pFile = NULL; + } +} + +CStdString LibSndFileFile::GetExtension() +{ + return ".wav"; +} diff --git a/orkbasecxx/audiofile/LibSndFileFile.h b/orkbasecxx/audiofile/LibSndFileFile.h new file mode 100644 index 0000000..e0516a8 --- /dev/null +++ b/orkbasecxx/audiofile/LibSndFileFile.h @@ -0,0 +1,46 @@ +/* + * Oreka -- A media capture and retrieval platform + * + * Copyright (C) 2005, orecx LLC + * + * http://www.orecx.com + * + * This program is free software, distributed under the terms of + * the GNU General Public License. + * Please refer to http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef __LIBSNDFILEFILE_H__ +#define __LIBSNDFILEFILE_H__ + + +#include "StdString.h" +#include "AudioCapture.h" +#include "sndfile.h" +#include "AudioFile.h" + + +/** file accessor class for all file types supported by the libsndfile library. + The library can be found at http://www.mega-nerd.com/libsndfile/ +*/ +class LibSndFileFile : public AudioFile +{ +public: + LibSndFileFile(int fileFormat); // fileFormat is described at http://www.mega-nerd.com/libsndfile/api.html + ~LibSndFileFile(); + + void Open(CStdString& filename, fileOpenModeEnum mode, bool stereo = false, int sampleRate = 8000); + void Close(); + + void WriteChunk(AudioChunkRef chunkRef); + int ReadChunkMono(AudioChunkRef& chunk); + + CStdString GetExtension(); +private: + SF_INFO m_fileInfo; + SNDFILE* m_pFile; +}; + +#endif + diff --git a/orkbasecxx/audiofile/Makefile.am b/orkbasecxx/audiofile/Makefile.am new file mode 100644 index 0000000..d737e11 --- /dev/null +++ b/orkbasecxx/audiofile/Makefile.am @@ -0,0 +1,6 @@ +METASOURCES = AUTO +noinst_LTLIBRARIES = libaudiofile.la +libaudiofile_la_SOURCES = MediaChunkFile.cpp AudioFile.cpp LibSndFileFile.cpp PcmFile.cpp +AM_CPPFLAGS = -D_REENTRANT +libaudiofile_la_LIBADD = +INCLUDES = -I@top_srcdir@ -I../../orkbasecxx diff --git a/orkbasecxx/audiofile/MediaChunkFile.cpp b/orkbasecxx/audiofile/MediaChunkFile.cpp new file mode 100644 index 0000000..47b2e8b --- /dev/null +++ b/orkbasecxx/audiofile/MediaChunkFile.cpp @@ -0,0 +1,154 @@ +/* + * Oreka -- A media capture and retrieval platform + * + * Copyright (C) 2005, orecx LLC + * + * http://www.orecx.com + * + * This program is free software, distributed under the terms of + * the GNU General Public License. + * Please refer to http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "MediaChunkFile.h" + +#define MAX_CHUNK_SIZE 100000 + + +MediaChunkFile::MediaChunkFile() +{ + m_stream = NULL; + m_mode = READ; + m_numChunksWritten = 0; + m_sampleRate = 0; +} + +MediaChunkFile::~MediaChunkFile() +{ + Close(); +} + + +void MediaChunkFile::Close() +{ + if(m_stream) + { + ACE_OS::fclose(m_stream); + m_stream = NULL; + } +} + +void MediaChunkFile::WriteChunk(AudioChunkRef chunkRef) +{ + if(chunkRef.get() == NULL) + { + return; + } + if(chunkRef->GetDetails()->m_numBytes == 0) + { + return; + } + + unsigned int numWritten = 0; + bool writeError = false; + if (m_stream) + { + int tmp = sizeof(AudioChunkDetails); + numWritten = ACE_OS::fwrite(chunkRef->GetDetails(), sizeof(AudioChunkDetails), 1, m_stream); + if(numWritten != 1) + { + writeError = true; + } + numWritten = ACE_OS::fwrite(chunkRef->m_pBuffer, sizeof(char), chunkRef->GetNumBytes(), m_stream); + if(numWritten != chunkRef->GetNumBytes()) + { + writeError = true; + } + } + else + { + throw(CStdString("Write attempt on unopened file:")+ m_filename); + } + + if (writeError) + { + throw(CStdString("Could not write to file:")+ m_filename); + } +} + +int MediaChunkFile::ReadChunkMono(AudioChunkRef& chunkRef) +{ + unsigned int numRead = 0; + bool readError = false; + + if (m_stream) + { + chunkRef.reset(new AudioChunk()); + short temp[MAX_CHUNK_SIZE]; + numRead = ACE_OS::fread(temp, sizeof(AudioChunkDetails), 1, m_stream); + if(numRead == 1) + { + AudioChunkDetails details; + memcpy(&details, temp, sizeof(AudioChunkDetails)); + + if(details.m_marker != MEDIA_CHUNK_MARKER) + { + throw(CStdString("Invalid marker in file:")+ m_filename); + } + if(details.m_numBytes >= MAX_CHUNK_SIZE) + { + throw(CStdString("Chunk too big in file:")+ m_filename); + } + else + { + numRead = ACE_OS::fread(temp, sizeof(char), details.m_numBytes, m_stream); + if(numRead != details.m_numBytes) + { + throw(CStdString("Incomplete chunk in file:")+ m_filename); + } + chunkRef->SetBuffer(temp, details.m_numBytes, details); + } + } + } + else + { + throw(CStdString("Read attempt on unopened file:")+ m_filename); + } + + return numRead; +} + + +void MediaChunkFile::Open(CStdString& filename, fileOpenModeEnum mode, bool stereo, int sampleRate) +{ + if(m_sampleRate == 0) + { + m_sampleRate = sampleRate; + } + + if(!m_filename.Equals(filename)) + { + m_filename = filename + GetExtension(); + } + m_stream = NULL; + m_mode = mode; + if (mode == READ) + { + m_stream = ACE_OS::fopen((PCSTR)m_filename, "rb"); + } + else + { + RecursiveMkdir(m_filename); + m_stream = ACE_OS::fopen((PCSTR)m_filename, "wb"); + } + if(!m_stream) + { + throw(CStdString("Could not open file: ") + m_filename); + } +} + +CStdString MediaChunkFile::GetExtension() +{ + return ".mcf"; +} diff --git a/orkbasecxx/audiofile/MediaChunkFile.h b/orkbasecxx/audiofile/MediaChunkFile.h new file mode 100644 index 0000000..b8e69ed --- /dev/null +++ b/orkbasecxx/audiofile/MediaChunkFile.h @@ -0,0 +1,40 @@ +/* + * Oreka -- A media capture and retrieval platform + * + * Copyright (C) 2005, orecx LLC + * + * http://www.orecx.com + * + * This program is free software, distributed under the terms of + * the GNU General Public License. + * Please refer to http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef __MEDIACHUNKFILE_H__ +#define __MEDIACHUNKFILE_H__ + +#include "audiofile/AudioFile.h" + + +/** File class for saving audio chunks as-is */ +class MediaChunkFile : public AudioFile +{ +public: + MediaChunkFile(); + ~MediaChunkFile(); + + void Open(CStdString& filename, fileOpenModeEnum mode, bool stereo = false, int sampleRate = 8000); + void Close(); + + void WriteChunk(AudioChunkRef chunkRef); + int ReadChunkMono(AudioChunkRef& chunkRef); + + CStdString GetExtension(); +protected: + + FILE* m_stream; +}; + +#endif + diff --git a/orkbasecxx/audiofile/PcmFile.cpp b/orkbasecxx/audiofile/PcmFile.cpp new file mode 100644 index 0000000..9d1a6d0 --- /dev/null +++ b/orkbasecxx/audiofile/PcmFile.cpp @@ -0,0 +1,117 @@ +/* + * Oreka -- A media capture and retrieval platform + * + * Copyright (C) 2005, orecx LLC + * + * http://www.orecx.com + * + * This program is free software, distributed under the terms of + * the GNU General Public License. + * Please refer to http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "PcmFile.h" + +PcmFile::PcmFile() +{ + m_stream = NULL; + m_mode = READ; + m_numChunksWritten = 0; + m_sampleRate = 0; +} + +PcmFile::~PcmFile() +{ + Close(); +} + + +void PcmFile::Close() +{ + if(m_stream) + { + ACE_OS::fclose(m_stream); + m_stream = NULL; + } +} + +void PcmFile::WriteChunk(AudioChunkRef chunkRef) +{ + if(chunkRef.get() == NULL) + { + return; + } + if(chunkRef->GetDetails()->m_numBytes == 0) + { + return; + } + + unsigned int numWritten = 0; + if (m_stream) + { + numWritten = ACE_OS::fwrite(chunkRef->m_pBuffer, sizeof(short), chunkRef->GetNumSamples(), m_stream); + } + else + { + throw(CStdString("Write attempt on unopened file:")+ m_filename); + } + + if (numWritten != chunkRef->GetNumSamples()) + { + throw(CStdString("Could not write to file:")+ m_filename); + } +} + +int PcmFile::ReadChunkMono(AudioChunkRef& chunkRef) +{ + unsigned int numRead = 0; + if (m_stream) + { + chunkRef.reset(new AudioChunk()); + short temp[PCM_FILE_DEFAULT_CHUNK_NUM_SAMPLES]; + numRead = ACE_OS::fread(temp, sizeof(short), PCM_FILE_DEFAULT_CHUNK_NUM_SAMPLES, m_stream); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + chunkRef->SetBuffer(temp, sizeof(short)*numRead, details); + } + else + { + throw(CStdString("Read attempt on unopened file:")+ m_filename); + } + return numRead; +} + + +void PcmFile::Open(CStdString& filename, fileOpenModeEnum mode, bool stereo, int sampleRate) +{ + if(m_sampleRate == 0) + { + m_sampleRate = sampleRate; + } + + if(!m_filename.Equals(filename)) + { + m_filename = filename + ".pcm"; + } + m_stream = NULL; + m_mode = mode; + if (mode == READ) + { + m_stream = ACE_OS::fopen((PCSTR)m_filename, "rb"); + } + else + { + RecursiveMkdir(m_filename); + m_stream = ACE_OS::fopen((PCSTR)m_filename, "wb"); + } + if(!m_stream) + { + throw(CStdString("Could not open file: ") + m_filename); + } +} + +CStdString PcmFile::GetExtension() +{ + return ".pcm"; +} diff --git a/orkbasecxx/audiofile/PcmFile.h b/orkbasecxx/audiofile/PcmFile.h new file mode 100644 index 0000000..91c1325 --- /dev/null +++ b/orkbasecxx/audiofile/PcmFile.h @@ -0,0 +1,41 @@ +/* + * Oreka -- A media capture and retrieval platform + * + * Copyright (C) 2005, orecx LLC + * + * http://www.orecx.com + * + * This program is free software, distributed under the terms of + * the GNU General Public License. + * Please refer to http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef __PCMFILE_H__ +#define __PCMFILE_H__ + +#include "audiofile/AudioFile.h" + +#define PCM_FILE_DEFAULT_CHUNK_NUM_SAMPLES 8000 + +/** File class for raw 16 bit signed PCM output */ +class PcmFile : public AudioFile +{ +public: + PcmFile(); + ~PcmFile(); + + void Open(CStdString& filename, fileOpenModeEnum mode, bool stereo = false, int sampleRate = 8000); + void Close(); + + void WriteChunk(AudioChunkRef chunkRef); + int ReadChunkMono(AudioChunkRef& chunkRef); + + CStdString GetExtension(); +protected: + + FILE* m_stream; +}; + +#endif + |