1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7     See the AUTHORS file for more details.
8 
9     This program is free software; you can redistribute it and/or
10     modify it under the terms of the GNU General Public License as
11     published by the Free Software Foundation; either version 2 of the
12     License, or (at your option) any later version.  See the file
13     COPYING included with this distribution for more information.
14 */
15 
16 #ifndef RG_PLAYABLE_AUDIO_FILE_H
17 #define RG_PLAYABLE_AUDIO_FILE_H
18 
19 #include "base/Instrument.h"
20 #include "RingBuffer.h"
21 #include "AudioFile.h"
22 #include "AudioCache.h"
23 
24 #include <string>
25 #include <map>
26 
27 namespace Rosegarden
28 {
29 
30 class RingBufferPool;
31 
32 
33 class PlayableAudioFile
34 {
35 public:
36     typedef float sample_t;
37 
38     PlayableAudioFile(InstrumentId instrumentId,
39                       AudioFile *audioFile,
40                       const RealTime &startTime,
41                       const RealTime &startIndex,
42                       const RealTime &duration,
43                       size_t bufferSize = 4096,
44                       size_t smallFileSize = 131072,
45                       int targetChannels = -1, // default same as file
46                       int targetSampleRate = -1); // default same as file
47     ~PlayableAudioFile();
48 
49     static void setRingBufferPoolSizes(size_t n, size_t nframes);
50 
setStartTime(const RealTime & time)51     void setStartTime(const RealTime &time) { m_startTime = time; }
getStartTime()52     RealTime getStartTime() const { return m_startTime; }
53 
setDuration(const RealTime & time)54     void setDuration(const RealTime &time) { m_duration = time; }
getDuration()55     RealTime getDuration() const { return m_duration; }
getEndTime()56     RealTime getEndTime() const { return m_startTime + m_duration; }
57 
setStartIndex(const RealTime & time)58     void setStartIndex(const RealTime &time) { m_startIndex = time; }
getStartIndex()59     RealTime getStartIndex() const { return m_startIndex; }
60 
isSmallFile()61     bool isSmallFile() const { return m_isSmallFile; }
62 
63     // Get audio file for interrogation
64     //
getAudioFile()65     AudioFile* getAudioFile() const { return m_audioFile; }
66 
67     // Get instrument ID - we need to be able to map back
68     // at the GUI.
69     //
getInstrument()70     InstrumentId getInstrument() const { return m_instrumentId; }
71 
72     // Return the number of frames currently buffered.  The next call
73     // to getSamples on any channel is guaranteed to return at least
74     // this many samples.
75     //
76     size_t getSampleFramesAvailable();
77 
78     // Read samples from the given channel on the file and add them
79     // into the destination.
80     //
81     // If insufficient frames are available, this will leave the
82     // excess samples unchanged.
83     //
84     // Returns the actual number of samples written.
85     //
86     // If offset is non-zero, the samples will be written starting at
87     // offset frames from the start of the target block.
88     //
89     size_t addSamples(std::vector<sample_t *> &target,
90                       size_t channels, size_t nframes, size_t offset = 0);
91 
92     unsigned int getSourceChannels();
93     unsigned int getTargetChannels();
94     unsigned int getSourceSampleRate();
95     unsigned int getTargetSampleRate();
96 
97     unsigned int getBitsPerSample();
98     unsigned int getBytesPerFrame();
99 
100     // Clear out and refill the ring buffer for immediate
101     // (asynchronous) play.
102     //
103     void fillBuffers();
104 
105     // Clear out and refill the ring buffer (in preparation for
106     // playback) according to the proposed play time.
107     //
108     // This call and updateBuffers are not thread-safe (for
109     // performance reasons).  They should be called for all files
110     // sequentially within a single thread.
111     //
112     bool fillBuffers(const RealTime &currentTime);
113 
114     void clearBuffers();
115 
116     // Update the buffer during playback.
117     //
118     // This call and fillBuffers are not thread-safe (for performance
119     // reasons).  They should be called for all files sequentially
120     // within a single thread.
121     //
122     bool updateBuffers();
123 
124     // Has fillBuffers been called and completed yet?
125     //
isBuffered()126     bool isBuffered() const { return m_currentScanPoint > m_startIndex; }
127 
128     // Has all the data in this file now been read into the buffers?
129     //
isFullyBuffered()130     bool isFullyBuffered() const { return m_isSmallFile || m_fileEnded; }
131 
132     // Stop playing this file.
133     //
cancel()134     void cancel() { m_fileEnded = true; }
135 
136     // Segment id that allows us to crosscheck against playing audio
137     // segments.
138     //
getRuntimeSegmentId()139     int getRuntimeSegmentId() const { return m_runtimeSegmentId; }
setRuntimeSegmentId(int id)140     void setRuntimeSegmentId(int id) { m_runtimeSegmentId = id; }
141 
142     // Auto fading of a playable audio file
143     //
isAutoFading()144     bool isAutoFading() const { return m_autoFade; }
setAutoFade(bool value)145     void setAutoFade(bool value) { m_autoFade = value; }
146 
getFadeInTime()147     RealTime getFadeInTime() const { return m_fadeInTime; }
setFadeInTime(const RealTime & time)148     void setFadeInTime(const RealTime &time)
149         { m_fadeInTime = time; }
150 
getFadeOutTime()151     RealTime getFadeOutTime() const { return m_fadeOutTime; }
setFadeOutTime(const RealTime & time)152     void setFadeOutTime(const RealTime &time)
153         { m_fadeOutTime = time; }
154 
155 
156 protected:
157     void initialise(size_t bufferSize, size_t smallFileSize);
158     void checkSmallFileCache(size_t smallFileSize);
159     bool scanTo(const RealTime &time);
160     void returnRingBuffers();
161 
162     RealTime              m_startTime;
163     RealTime              m_startIndex;
164     RealTime              m_duration;
165 
166     // Performance file handle - must open non-blocking to
167     // allow other potential PlayableAudioFiles access to
168     // the same file.
169     //
170     std::ifstream        *m_file;
171 
172     // AudioFile handle
173     //
174     AudioFile            *m_audioFile;
175 
176     // Originating Instrument Id
177     //
178     InstrumentId          m_instrumentId;
179 
180     int                   m_targetChannels;
181     int                   m_targetSampleRate;
182 
183     bool                  m_fileEnded;
184     bool                  m_firstRead;
185     static size_t         m_xfadeFrames;
186     int                   m_runtimeSegmentId;
187 
188     static AudioCache     m_smallFileCache;
189     bool                  m_isSmallFile;
190 
191     static std::vector<sample_t *> m_workBuffers;
192     static size_t         m_workBufferSize;
193 
194     static char          *m_rawFileBuffer;
195     static size_t         m_rawFileBufferSize;
196 
197     RingBuffer<sample_t>  **m_ringBuffers;
198     static RingBufferPool  *m_ringBufferPool;
199 
200     RealTime              m_currentScanPoint;
201     size_t                m_smallFileScanFrame;
202 
203     bool                  m_autoFade;
204     RealTime  m_fadeInTime;
205     RealTime  m_fadeOutTime;
206 
207 private:
208     PlayableAudioFile(const PlayableAudioFile &pAF); // not provided
209 };
210 
211 }
212 
213 #endif
214