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.
220 lines
6.6 KiB
220 lines
6.6 KiB
15 years ago
|
// -*- c-basic-offset: 4 -*-
|
||
|
|
||
|
/*
|
||
|
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.
|
||
|
*/
|
||
|
|
||
|
#ifndef _PLAYABLE_AUDIO_FILE_H_
|
||
|
#define _PLAYABLE_AUDIO_FILE_H_
|
||
|
|
||
|
#include "Instrument.h"
|
||
|
#include "RingBuffer.h"
|
||
|
#include "AudioFile.h"
|
||
|
#include "AudioCache.h"
|
||
|
|
||
|
#include <string>
|
||
|
#include <map>
|
||
|
|
||
|
namespace Rosegarden
|
||
|
{
|
||
|
|
||
|
class RingBufferPool;
|
||
|
|
||
|
|
||
|
class PlayableAudioFile
|
||
|
{
|
||
|
public:
|
||
|
typedef float sample_t;
|
||
|
|
||
|
PlayableAudioFile(InstrumentId instrumentId,
|
||
|
AudioFile *audioFile,
|
||
|
const RealTime &startTime,
|
||
|
const RealTime &startIndex,
|
||
|
const RealTime &duration,
|
||
|
size_t bufferSize = 4096,
|
||
|
size_t smallFileSize = 131072,
|
||
|
int targetChannels = -1, // default same as file
|
||
|
int targetSampleRate = -1); // default same as file
|
||
|
~PlayableAudioFile();
|
||
|
|
||
|
static void setRingBufferPoolSizes(size_t n, size_t nframes);
|
||
|
|
||
|
void setStartTime(const RealTime &time) { m_startTime = time; }
|
||
|
RealTime getStartTime() const { return m_startTime; }
|
||
|
|
||
|
void setDuration(const RealTime &time) { m_duration = time; }
|
||
|
RealTime getDuration() const { return m_duration; }
|
||
|
RealTime getEndTime() const { return m_startTime + m_duration; }
|
||
|
|
||
|
void setStartIndex(const RealTime &time) { m_startIndex = time; }
|
||
|
RealTime getStartIndex() const { return m_startIndex; }
|
||
|
|
||
|
bool isSmallFile() const { return m_isSmallFile; }
|
||
|
|
||
|
// Get audio file for interrogation
|
||
|
//
|
||
|
AudioFile* getAudioFile() const { return m_audioFile; }
|
||
|
|
||
|
// Get instrument ID - we need to be able to map back
|
||
|
// at the GUI.
|
||
|
//
|
||
|
InstrumentId getInstrument() const { return m_instrumentId; }
|
||
|
|
||
|
// Return the number of frames currently buffered. The next call
|
||
|
// to getSamples on any channel is guaranteed to return at least
|
||
|
// this many samples.
|
||
|
//
|
||
|
size_t getSampleFramesAvailable();
|
||
|
|
||
|
// Read samples from the given channel on the file and add them
|
||
|
// into the destination.
|
||
|
//
|
||
|
// If insufficient frames are available, this will leave the
|
||
|
// excess samples unchanged.
|
||
|
//
|
||
|
// Returns the actual number of samples written.
|
||
|
//
|
||
|
// If offset is non-zero, the samples will be written starting at
|
||
|
// offset frames from the start of the target block.
|
||
|
//
|
||
|
size_t addSamples(std::vector<sample_t *> &target,
|
||
|
size_t channels, size_t nframes, size_t offset = 0);
|
||
|
|
||
|
unsigned int getSourceChannels();
|
||
|
unsigned int getTargetChannels();
|
||
|
unsigned int getSourceSampleRate();
|
||
|
unsigned int getTargetSampleRate();
|
||
|
|
||
|
unsigned int getBitsPerSample();
|
||
|
unsigned int getBytesPerFrame();
|
||
|
|
||
|
// Clear out and refill the ring buffer for immediate
|
||
|
// (asynchronous) play.
|
||
|
//
|
||
|
void fillBuffers();
|
||
|
|
||
|
// Clear out and refill the ring buffer (in preparation for
|
||
|
// playback) according to the proposed play time.
|
||
|
//
|
||
|
// This call and updateBuffers are not thread-safe (for
|
||
|
// performance reasons). They should be called for all files
|
||
|
// sequentially within a single thread.
|
||
|
//
|
||
|
bool fillBuffers(const RealTime ¤tTime);
|
||
|
|
||
|
void clearBuffers();
|
||
|
|
||
|
// Update the buffer during playback.
|
||
|
//
|
||
|
// This call and fillBuffers are not thread-safe (for performance
|
||
|
// reasons). They should be called for all files sequentially
|
||
|
// within a single thread.
|
||
|
//
|
||
|
bool updateBuffers();
|
||
|
|
||
|
// Has fillBuffers been called and completed yet?
|
||
|
//
|
||
|
bool isBuffered() const { return m_currentScanPoint > m_startIndex; }
|
||
|
|
||
|
// Has all the data in this file now been read into the buffers?
|
||
|
//
|
||
|
bool isFullyBuffered() const { return m_isSmallFile || m_fileEnded; }
|
||
|
|
||
|
// Stop playing this file.
|
||
|
//
|
||
|
void cancel() { m_fileEnded = true; }
|
||
|
|
||
|
// Segment id that allows us to crosscheck against playing audio
|
||
|
// segments.
|
||
|
//
|
||
|
int getRuntimeSegmentId() const { return m_runtimeSegmentId; }
|
||
|
void setRuntimeSegmentId(int id) { m_runtimeSegmentId = id; }
|
||
|
|
||
|
// Auto fading of a playable audio file
|
||
|
//
|
||
|
bool isAutoFading() const { return m_autoFade; }
|
||
|
void setAutoFade(bool value) { m_autoFade = value; }
|
||
|
|
||
|
RealTime getFadeInTime() const { return m_fadeInTime; }
|
||
|
void setFadeInTime(const RealTime &time)
|
||
|
{ m_fadeInTime = time; }
|
||
|
|
||
|
RealTime getFadeOutTime() const { return m_fadeOutTime; }
|
||
|
void setFadeOutTime(const RealTime &time)
|
||
|
{ m_fadeOutTime = time; }
|
||
|
|
||
|
|
||
|
protected:
|
||
|
void initialise(size_t bufferSize, size_t smallFileSize);
|
||
|
void checkSmallFileCache(size_t smallFileSize);
|
||
|
bool scanTo(const RealTime &time);
|
||
|
void returnRingBuffers();
|
||
|
|
||
|
RealTime m_startTime;
|
||
|
RealTime m_startIndex;
|
||
|
RealTime m_duration;
|
||
|
|
||
|
// Performance file handle - must open non-blocking to
|
||
|
// allow other potential PlayableAudioFiles access to
|
||
|
// the same file.
|
||
|
//
|
||
|
std::ifstream *m_file;
|
||
|
|
||
|
// AudioFile handle
|
||
|
//
|
||
|
AudioFile *m_audioFile;
|
||
|
|
||
|
// Originating Instrument Id
|
||
|
//
|
||
|
InstrumentId m_instrumentId;
|
||
|
|
||
|
int m_targetChannels;
|
||
|
int m_targetSampleRate;
|
||
|
|
||
|
bool m_fileEnded;
|
||
|
bool m_firstRead;
|
||
|
static size_t m_xfadeFrames;
|
||
|
int m_runtimeSegmentId;
|
||
|
|
||
|
static AudioCache m_smallFileCache;
|
||
|
bool m_isSmallFile;
|
||
|
|
||
|
static std::vector<sample_t *> m_workBuffers;
|
||
|
static size_t m_workBufferSize;
|
||
|
|
||
|
static char *m_rawFileBuffer;
|
||
|
static size_t m_rawFileBufferSize;
|
||
|
|
||
|
RingBuffer<sample_t> **m_ringBuffers;
|
||
|
static RingBufferPool *m_ringBufferPool;
|
||
|
|
||
|
RealTime m_currentScanPoint;
|
||
|
size_t m_smallFileScanFrame;
|
||
|
|
||
|
bool m_autoFade;
|
||
|
RealTime m_fadeInTime;
|
||
|
RealTime m_fadeOutTime;
|
||
|
|
||
|
private:
|
||
|
PlayableAudioFile(const PlayableAudioFile &pAF); // not provided
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif
|