-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaudioFileReader.hpp
More file actions
142 lines (110 loc) · 4.14 KB
/
audioFileReader.hpp
File metadata and controls
142 lines (110 loc) · 4.14 KB
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
#ifndef AUDIOFILEREADER_HPP_
#define AUDIOFILEREADER_HPP_
#include <cstring>
#include <cassert>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <sonic.h>
#include <sox.h>
#include "attributes.hpp"
struct PACKED AudioFileInfo {
unsigned sampleRate;
unsigned numChannels;
size_t numSamples;
};
class AudioFileReader {
private:
std::atomic<bool> alive;
int error;
sox_format_t *audioFile;
AudioFileInfo fileInfo;
char *filename;
unsigned MAX_REQUEST;
unsigned MAX_PRE;
unsigned MAX_POST;
unsigned BUFFER_SIZE;
float *circleBuffer;
int *toConvert;
float *nil;
unsigned preValid;
unsigned postValid;
unsigned pos;
std::thread *readerThread;
std::mutex accessLock;
std::condition_variable bufferMoved;
std::condition_variable readRequest;
std::condition_variable resetRequest;
unsigned requestingReset;
HOT void preloaderLoop();
HOT void readInto(unsigned index, unsigned &head);
public:
AudioFileReader(const char *fname, unsigned maxRequestMilliseconds, unsigned maxRememberSeconds, unsigned maxPreloadSeconds);
~AudioFileReader();
USERET INLINE const AudioFileInfo &getFileInfo() const { return fileInfo; }
USERET bool loadFile(char *fname, unsigned maxRequestMilliseconds, unsigned maxRememberSeconds, unsigned maxPreloadSeconds);
size_t setBufferSettings(unsigned maxRequestMilliseconds, unsigned maxRememberSeconds, unsigned maxPreloadSeconds);
USERET size_t getMaxRequestBytes() const { return(sizeof(float) * MAX_REQUEST); }
USERET const void *readData(unsigned position, size_t numBytes);
INLINE void copyData(void *dest, unsigned position, size_t numBytes) { std::memcpy(dest, readData(position, numBytes), numBytes); }
INLINE USERET bool isAlive() const { return alive; }
INLINE USERET int err() const { return error; }
INLINE void kill() { alive = false; }
class AudioStretcher {
private:
AudioFileReader *const reader;
sonicStream stretcher;
unsigned inPos;
unsigned outPos;
float speed;
const size_t bufferSize; //Uses a 3 second buffer
void trashStreamData() {
sonicFlushStream(stretcher);
const register unsigned size = sonicSamplesAvailable(stretcher);
float *trash = new float[size * reader->fileInfo.numChannels];
sonicReadFloatFromStream(stretcher, trash, size);
delete[] trash;
}
public:
INLINE AudioStretcher(AudioFileReader *fileReader) : reader(fileReader), bufferSize(fileReader->fileInfo.sampleRate * fileReader->fileInfo.numChannels * 3) {
inPos = 0xffffffff;
outPos = 0xffffffff;
speed = 0.5f;
stretcher = sonicCreateStream(reader->fileInfo.sampleRate, reader->fileInfo.numChannels);
sonicSetSpeed(stretcher, speed);
}
INLINE unsigned copyData(void *dest, unsigned position, size_t numBytes) {
assert(numBytes % (sizeof(float) * reader->fileInfo.numChannels) == 0);
const size_t numSamples = numBytes / sizeof(float);
const size_t numMultiSamples = numSamples / reader->fileInfo.numChannels;
if (position != outPos) {
//we've skipped to a new position, so flush the buffer
trashStreamData();
inPos = position;
outPos = position;
}
//top off the buffer
while (inPos < outPos + bufferSize) {
const size_t requestMultiSamples = reader->getMaxRequestBytes() / (reader->fileInfo.numChannels * sizeof(float));
const size_t requestBytes = requestMultiSamples * reader->fileInfo.numChannels * sizeof(float);
sonicWriteFloatToStream(stretcher, (float*)reader->readData(inPos, requestBytes), requestMultiSamples);
inPos += requestBytes / sizeof(float);
}
//if there aren't enough samples ready, wait for sonic to process them
while ((unsigned) sonicSamplesAvailable(stretcher) < numMultiSamples) std::this_thread::yield();
sonicReadFloatFromStream(stretcher, (float*)dest, numMultiSamples);
outPos += (unsigned) ((float) numSamples * speed);
return (unsigned) ((float) numSamples * speed);
}
INLINE void setSpeed(float slow) {
trashStreamData();
inPos = 0xffffffff;
outPos = 0xffffffff;
speed = slow;
sonicSetSpeed(stretcher, speed);
}
INLINE ~AudioStretcher() { sonicDestroyStream(stretcher); }
} *audioStretcher;
};
#endif /* AUDIOFILEREADER_HPP_ */