You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rosegarden/src/sound/SoundFile.cpp

295 lines
6.8 KiB

/*
Rosegarden
A sequencer and musical notation editor.
This program is Copyright 2000-2008
Guillaume Laurent <glaurent@telegraph-road.org>,
Chris Cannam <cannam@all-day-breakfast.com>,
Richard Bown <bownie@bownie.com>
The moral right of the authors to claim authorship of this work
has been asserted.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
*/
#include "SoundFile.h"
#include "Profiler.h"
//#define DEBUG_SOUNDFILE 1
namespace Rosegarden
{
SoundFile::SoundFile(const std::string &fileName):
m_fileName(fileName),
m_readChunkPtr( -1),
m_readChunkSize(4096), // 4k blocks
m_inFile(0),
m_outFile(0),
m_loseBuffer(false),
m_fileSize(0)
{}
// Tidies up for any dervied classes
//
SoundFile::~SoundFile()
{
if (m_inFile) {
m_inFile->close();
delete m_inFile;
}
if (m_outFile) {
m_outFile->close();
delete m_outFile;
}
}
// Read in a specified number of bytes and return them
// as a string.
//
std::string
SoundFile::getBytes(std::ifstream *file, unsigned int numberOfBytes)
{
if (file->eof()) {
// Reset the input stream so it's operational again
//
file->clear();
throw(BadSoundFileException(m_fileName, "SoundFile::getBytes() - EOF encountered"));
}
if (!(*file)) {
std::cerr << "SoundFile::getBytes() - stream is not well";
}
std::string rS;
char *fileBytes = new char[numberOfBytes];
file->read(fileBytes, numberOfBytes);
for (int i = 0; i < file->gcount(); i++)
rS += (unsigned char)fileBytes[i];
#ifdef DEBUG_SOUNDFILE
// complain but return
//
if (rS.length() < numberOfBytes)
std::cerr << "SoundFile::getBytes() - couldn't get all bytes ("
<< rS.length() << " from " << numberOfBytes << ")"
<< std::endl;
#endif
// clear down
delete [] fileBytes;
return rS;
}
// Read a specified number of bytes into a buffer.
//
size_t
SoundFile::getBytes(std::ifstream *file, char *buf, size_t n)
{
if (!(*file)) {
std::cerr << "SoundFile::getBytes() - stream is not well";
return 0;
}
if (file->eof()) {
file->clear();
return 0;
}
file->read(buf, n);
return file->gcount();
}
// A buffered read based on the current file handle.
//
std::string
SoundFile::getBytes(unsigned int numberOfBytes)
{
if (m_inFile == 0)
throw(BadSoundFileException(m_fileName, "SoundFile::getBytes - no open file handle"));
if (m_inFile->eof()) {
// Reset the input stream so it's operational again
//
m_inFile->clear();
throw(BadSoundFileException(m_fileName, "SoundFile::getBytes() - EOF encountered"));
}
// If this flag is set we dump the buffer and re-read it -
// should be set if specialised class is scanning about
// when we're doing buffered reads
//
if (m_loseBuffer) {
m_readChunkPtr = -1;
m_loseBuffer = false;
}
std::string rS;
char *fileBytes = new char[m_readChunkSize];
int oldLength;
while (rS.length() < numberOfBytes && !m_inFile->eof()) {
if (m_readChunkPtr == -1) {
// clear buffer
m_readBuffer = "";
// reset read pointer
m_readChunkPtr = 0;
// Try to read the whole chunk
//
m_inFile->read(fileBytes, m_readChunkSize);
// file->gcount holds the number of bytes we've actually read
// so copy them across into our string
//
for (int i = 0; i < m_inFile->gcount(); i++)
m_readBuffer += (unsigned char)fileBytes[i];
}
// Can we fulfill our request at this pass? If so read the
// bytes across and we'll exit at the end of this loop.
// m_readChunkPtr keeps our position for next time.
//
if (numberOfBytes - rS.length() <= m_readBuffer.length() -
m_readChunkPtr) {
oldLength = rS.length();
rS += m_readBuffer.substr(m_readChunkPtr,
numberOfBytes - oldLength);
m_readChunkPtr += rS.length() - oldLength;
} else {
// Fill all we can this time and reset the m_readChunkPtr
// so that we fetch another chunk of bytes from the file.
//
rS += m_readBuffer.substr(m_readChunkPtr,
m_readChunkSize - m_readChunkPtr);
m_readChunkPtr = -1;
}
// If we're EOF here we must've read and copied across everything
// we can do. Reset and break out.
//
if (m_inFile->eof()) {
m_inFile->clear();
break;
}
}
#ifdef DEBUG_SOUNDFILE
// complain but return
//
if (rS.length() < numberOfBytes)
std::cerr << "SoundFile::getBytes() buffered - couldn't get all bytes ("
<< rS.length() << " from " << numberOfBytes << ")"
<< std::endl;
#endif
delete [] fileBytes;
// Reset and return if EOF
//
if (m_inFile->eof())
m_inFile->clear();
return rS;
}
// Write out a sequence of FileBytes to the stream
//
void
SoundFile::putBytes(std::ofstream *file,
const std::string oS)
{
for (unsigned int i = 0; i < oS.length(); i++)
*file << (FileByte) oS[i];
}
void
SoundFile::putBytes(std::ofstream *file, const char *buffer, size_t n)
{
file->write(buffer, n);
}
// Clip off any path from the filename
std::string
SoundFile::getShortFilename() const
{
std::string rS = m_fileName;
unsigned int pos = rS.find_last_of("/");
if (pos > 0 && ( pos + 1 ) < rS.length())
rS = rS.substr(pos + 1, rS.length());
return rS;
}
// Turn a little endian binary std::string into an integer
//
int
SoundFile::getIntegerFromLittleEndian(const std::string &s)
{
int r = 0;
for (unsigned int i = 0; i < s.length(); i++) {
r += (int)(((FileByte)s[i]) << (i * 8));
}
return r;
}
// Turn a value into a little endian string of "length"
//
std::string
SoundFile::getLittleEndianFromInteger(unsigned int value, unsigned int length)
{
std::string r = "";
do {
r += (unsigned char)((long)((value >> (8 * r.length())) & 0xff));
} while (r.length() < length);
return r;
}
int
SoundFile::getIntegerFromBigEndian(const std::string &s)
{
return 0;
}
std::string
SoundFile::getBigEndianFromInteger(unsigned int value, unsigned int length)
{
std::string r;
return r;
}
}