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.
295 lines
6.8 KiB
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;
|
|
}
|
|
|
|
|
|
}
|
|
|