summaryrefslogtreecommitdiffstats
path: root/src/sound/PlayableAudioFile.h
blob: 648ad4ca987bdaf42f9be8a4e581c5c87e4d2b68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// -*- c-basic-offset: 4 -*-

/*
    Rosegarden
    A sequencer and musical notation editor.

    This program is Copyright 2000-2008
        Guillaume Laurent   <[email protected]>,
        Chris Cannam        <[email protected]>,
        Richard Bown        <[email protected]>

    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 &currentTime);

    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