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/MP3AudioFile.cpp

328 lines
6.9 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 "MP3AudioFile.h"
#ifdef HAVE_LIBMAD
#include <mad.h>
namespace Rosegarden
{
/*
* This is a private message structure. A generic pointer to this structure
* is passed to each of the callback functions. Put here any data you need
* to access from within the callbacks.
*/
struct player
{
unsigned char const *start;
unsigned long length;
//int default_driver;
//ao_device *device;
//ao_sample_format format;
//class SoundTouch *touch;
};
MP3AudioFile::MP3AudioFile(const unsigned int &id,
const std::string &name,
const std::string &fileName):
AudioFile(id, name, fileName)
{
m_type = MP3;
}
MP3AudioFile::MP3AudioFile(const std::string &fileName,
unsigned int /*channels*/,
unsigned int /*sampleRate*/,
unsigned int /*bytesPerSecond*/,
unsigned int /*bytesPerSample*/,
unsigned int /*bitsPerSample*/):
AudioFile(0, std::string(""), fileName)
{
m_type = MP3;
}
MP3AudioFile::~MP3AudioFile()
{}
bool
MP3AudioFile::open()
{
// if already open
if (m_inFile && (*m_inFile))
return true;
m_inFile = new std::ifstream(m_fileName.c_str(),
std::ios::in | std::ios::binary);
if (!(*m_inFile)) {
m_type = UNKNOWN;
return false;
}
// Get the file size and store it for comparison later
m_fileSize = m_fileInfo->size();
try {
parseHeader();
} catch (BadSoundFileException s) {
throw(s);
}
return true;
}
bool
MP3AudioFile::write()
{
return false;
}
void
MP3AudioFile::close()
{}
void
MP3AudioFile::parseHeader()
{
const std::string MP3_TAG("TAG");
if (m_inFile == 0)
return ;
// store size conveniently
m_fileSize = m_fileInfo->size();
if (m_fileSize == 0) {
std::string mess = std::string("\"") + m_fileName +
std::string("\" is empty - invalid MP3 file");
throw(mess);
}
// seek to beginning
m_inFile->seekg(0, std::ios::beg);
// get some header information
//
const int bufferLength = 3096;
std::string hS = getBytes(bufferLength);
bool foundMP3 = false;
for (unsigned int i = 0; i < hS.length() - 1; ++i) {
if ((hS[i] & 0xff) == 0xff && (hS[i + 1] & 0xe0) == 0xe0) {
foundMP3 = true;
break;
}
}
if (foundMP3 == false || (int)hS.length() < bufferLength) {
std::string mess = std::string("\"") + m_fileName +
std::string("\" doesn't appear to be a valid MP3 file");
throw(mess);
}
// guess most likely values - these are reset during decoding
m_channels = 2;
m_sampleRate = 44100;
mad_synth synth;
mad_frame frame;
mad_stream stream;
mad_synth_init(&synth);
mad_stream_init(&stream);
mad_frame_init(&frame);
/*
mad_stream_buffer(&stream, hS.data(), hS.length());
if (mad_header_decode(&frame.header, &stream) == -1)
{
throw("Can't decode header");
}
mad_frame_decode(&frame, &stream);
m_sampleRate = frame.header.samplerate;
mad_synth_frame(&synth, &frame);
struct mad_pcm *pcm = &synth.pcm;
m_channels = pcm->channels;
*/
/*
struct player player;
struct mad_decoder decoder;
struct stat stat;
void *fdm;
int result;
if (fstat(fd, &stat) == -1 ||
stat.st_size == 0)
return 0;
fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (fdm == MAP_FAILED) {
fprintf(stderr, "mmap failed, aborting...\n");
return 0;
}
player.start = (unsigned char *)fdm;
player.length = stat.st_size;
player.default_driver = ao_default_driver_id();
player.device = NULL;
player.touch = new SoundTouch;
player.touch->setTempo(tempo);
player.touch->setPitch(pitch);
mad_decoder_init(&decoder, &player,
input, 0 , 0 , process_output,
decode_error, 0);
result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
mad_decoder_finish(&decoder);
delete player.touch;
ao_close(player.device);
if (munmap((void *)player.start, stat.st_size) == -1)
return 4;
return result;
*/
}
std::streampos
MP3AudioFile::getDataOffset()
{
return 0;
}
bool
MP3AudioFile::scanTo(const RealTime & /*time*/)
{
return false;
}
bool
MP3AudioFile::scanTo(std::ifstream * /*file*/, const RealTime & /*time*/)
{
return false;
}
// Scan forward in a file by a certain amount of time
//
bool
MP3AudioFile::scanForward(const RealTime & /*time*/)
{
return false;
}
bool
MP3AudioFile::scanForward(std::ifstream * /*file*/, const RealTime & /*time*/)
{
return false;
}
// Return a number of samples - caller will have to
// de-interleave n-channel samples themselves.
//
std::string
MP3AudioFile::getSampleFrames(std::ifstream * /*file*/,
unsigned int /*frames*/)
{
return "";
}
unsigned int
MP3AudioFile::getSampleFrames(std::ifstream * /*file*/,
char * /* buf */,
unsigned int /*frames*/)
{
return 0;
}
std::string
MP3AudioFile::getSampleFrames(unsigned int /*frames*/)
{
return "";
}
// Return a number of (possibly) interleaved samples
// over a time slice from current file pointer position.
//
std::string
MP3AudioFile::getSampleFrameSlice(std::ifstream * /*file*/,
const RealTime & /*time*/)
{
return "";
}
std::string
MP3AudioFile::getSampleFrameSlice(const RealTime & /*time*/)
{
return "";
}
// Append a string of samples to an already open (for writing)
// audio file.
//
bool
MP3AudioFile::appendSamples(const std::string & /*buffer*/)
{
return false;
}
bool
MP3AudioFile::appendSamples(const char * /*buffer*/, unsigned int)
{
return false;
}
// Get the length of the sample in Seconds/Microseconds
//
RealTime
MP3AudioFile::getLength()
{
return RealTime(0, 0);
}
void
MP3AudioFile::printStats()
{}
}
#endif // HAVE_LIBMAD