Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/MD_package/MDAudioUtility.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 160 - (show annotations) (download) (as text)
Tue Aug 13 04:25:38 2019 UTC (4 years, 7 months ago) by toshinagata1964
File MIME type: text/x-csrc
File size: 8863 byte(s)
Improve audio output when the output device is working at other than 44100 Hz
1 /*
2 * MDAudioUtility.c
3 * Alchemusica
4 *
5 * Created by Toshi Nagata on 09/11/05.
6 * Copyright 2009-2011 Toshi Nagata. All rights reserved.
7 *
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation version 2 of the License.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 */
17
18 #include "MDAudioUtility.h"
19
20 #pragma mark ====== MDRingBuffer ======
21
22 static UInt32
23 sNextPowerOfTwo(UInt32 x)
24 {
25 UInt32 n;
26 for (n = 1; n != 0; n <<= 1) {
27 if (n > x)
28 return n;
29 }
30 return 0;
31 }
32
33 MDRingBuffer *
34 MDRingBufferNew(void)
35 {
36 return (MDRingBuffer *)calloc(sizeof(MDRingBuffer), 1);
37 }
38
39 int
40 MDRingBufferAllocate(MDRingBuffer *ring, int nChannels, UInt32 bytesPerFrame, UInt32 capacityFrames)
41 {
42 UInt32 allocSize;
43 Byte *p;
44 int i;
45 UInt32 j;
46
47 MDRingBufferDeallocate(ring);
48 capacityFrames = sNextPowerOfTwo(capacityFrames);
49
50 ring->numberChannels = 1; /* Assumes non-interleaved stream */
51 ring->numberBuffers = nChannels;
52 ring->bytesPerFrame = bytesPerFrame;
53 ring->capacityFrames = capacityFrames;
54 ring->capacityFramesMask = capacityFrames - 1;
55 ring->capacityBytes = bytesPerFrame * capacityFrames;
56
57 // put everything in one memory allocation, first the pointers, then the deinterleaved channels
58 allocSize = (ring->capacityBytes + sizeof(Byte *)) * ring->numberBuffers;
59 p = (Byte *)malloc(allocSize);
60 memset(p, 0, allocSize);
61 ring->buffers = (Byte **)p;
62 p += ring->numberBuffers * sizeof(Byte *);
63 for (i = 0; i < ring->numberBuffers; ++i) {
64 ring->buffers[i] = p;
65 p += ring->capacityBytes;
66 }
67
68 for (j = 0; j < kMDRingTimeBoundsQueueSize; ++j)
69 {
70 ring->timeBoundsQueue[j].startTime = 0;
71 ring->timeBoundsQueue[j].endTime = 0;
72 ring->timeBoundsQueue[j].updateCounter = 0;
73 }
74 ring->timeBoundsQueuePtr = 0;
75 return kMDRingBufferError_OK;
76 }
77
78 void
79 MDRingBufferDeallocate(MDRingBuffer *ring)
80 {
81 if (ring == NULL)
82 return;
83 if (ring->buffers != NULL) {
84 free(ring->buffers);
85 ring->buffers = NULL;
86 }
87 ring->numberChannels = 0;
88 ring->numberBuffers = 0;
89 ring->capacityBytes = 0;
90 ring->capacityFrames = 0;
91 }
92
93 void
94 MDRingBufferRelease(MDRingBuffer *ring)
95 {
96 MDRingBufferDeallocate(ring);
97 free(ring);
98 }
99
100 static inline void
101 sZeroRange(Byte **buffers, int nchannels, int offset, int nbytes)
102 {
103 while (--nchannels >= 0) {
104 memset(*buffers + offset, 0, nbytes);
105 ++buffers;
106 }
107 }
108
109 static inline void
110 sStoreABL(Byte **buffers, int destOffset, const AudioBufferList *abl, int srcOffset, int nbytes)
111 {
112 int nchannels = abl->mNumberBuffers;
113 const AudioBuffer *src = abl->mBuffers;
114 // printf("Store %d bytes at [%d] from [%d]\n", nbytes, destOffset, srcOffset);
115 while (--nchannels >= 0) {
116 memcpy(*buffers + destOffset, (Byte *)src->mData + srcOffset, nbytes);
117 ++buffers;
118 ++src;
119 }
120 }
121
122 static inline void
123 sFetchABL(AudioBufferList *abl, int destOffset, Byte **buffers, int srcOffset, int nbytes)
124 {
125 int nchannels = abl->mNumberBuffers;
126 AudioBuffer *dest = abl->mBuffers;
127 // printf("Fetch %d bytes from [%d] to [%d]\n", nbytes, srcOffset, destOffset);
128 while (--nchannels >= 0) {
129 memcpy((Byte *)dest->mData + destOffset, *buffers + srcOffset, nbytes);
130 ++buffers;
131 ++dest;
132 }
133 }
134
135 int
136 MDRingBufferStore(MDRingBuffer *ring, const AudioBufferList *abl, UInt32 framesToWrite, MDSampleTime startWrite)
137 {
138 MDSampleTime endWrite;
139
140 if (abl->mNumberBuffers != ring->numberBuffers)
141 return kMDRingBufferError_NumberBuffersMismatch;
142
143 if (framesToWrite > ring->capacityFrames)
144 return kMDRingBufferError_TooMuch; // too big!
145
146 endWrite = startWrite + framesToWrite;
147
148 if (startWrite < MDRingBufferEndTime(ring)) {
149 // going backwards, throw everything out
150 MDRingBufferSetTimeBounds(ring, startWrite, startWrite);
151 } else if (endWrite - MDRingBufferStartTime(ring) <= ring->capacityFrames) {
152 // the buffer has not yet wrapped and will not need to
153 } else {
154 // advance the start time past the region we are about to overwrite
155 MDSampleTime newStart = endWrite - ring->capacityFrames; // one buffer of time behind where we're writing
156 MDSampleTime newEnd = MDRingBufferEndTime(ring);
157 if (newStart > newEnd)
158 newEnd = newStart;
159 MDRingBufferSetTimeBounds(ring, newStart, newEnd);
160 }
161
162 // write the new frames
163 Byte **buffers = ring->buffers;
164 int nchannels = ring->numberChannels;
165 int offset0, offset1, nbytes;
166 MDSampleTime curEnd = MDRingBufferEndTime(ring);
167
168 if (startWrite > curEnd) {
169 // we are skipping some samples, so zero the range we are skipping
170 offset0 = MDRingBufferFrameOffset(ring, curEnd);
171 offset1 = MDRingBufferFrameOffset(ring, startWrite);
172 if (offset0 < offset1)
173 sZeroRange(buffers, nchannels, offset0, offset1 - offset0);
174 else {
175 sZeroRange(buffers, nchannels, offset0, ring->capacityBytes - offset0);
176 sZeroRange(buffers, nchannels, 0, offset1);
177 }
178 offset0 = offset1;
179 } else {
180 offset0 = MDRingBufferFrameOffset(ring, startWrite);
181 }
182
183 offset1 = MDRingBufferFrameOffset(ring, endWrite);
184 if (offset0 < offset1)
185 sStoreABL(buffers, offset0, abl, 0, offset1 - offset0);
186 else {
187 nbytes = ring->capacityBytes - offset0;
188 sStoreABL(buffers, offset0, abl, 0, nbytes);
189 sStoreABL(buffers, 0, abl, nbytes, offset1);
190 }
191
192 // now update the end time
193 MDRingBufferSetTimeBounds(ring, MDRingBufferStartTime(ring), endWrite);
194
195 return kMDRingBufferError_OK; // success
196 }
197
198 int
199 MDRingBufferFetch(MDRingBuffer *ring, AudioBufferList *abl, UInt32 nFrames, MDSampleTime startRead, bool aheadOK)
200 {
201 MDSampleTime endRead = startRead + nFrames;
202 int err;
203
204 if (abl->mNumberBuffers != ring->numberBuffers)
205 return kMDRingBufferError_NumberBuffersMismatch;
206
207 err = MDRingBufferCheckTimeBounds(ring, startRead, endRead, aheadOK);
208 if (err)
209 return err;
210
211 Byte **buffers = ring->buffers;
212 int offset0 = MDRingBufferFrameOffset(ring, startRead);
213 int offset1 = MDRingBufferFrameOffset(ring, endRead);
214 int nbytes;
215
216 if (offset0 < offset1) {
217 sFetchABL(abl, 0, buffers, offset0, nbytes = offset1 - offset0);
218 } else {
219 nbytes = ring->capacityBytes - offset0;
220 sFetchABL(abl, 0, buffers, offset0, nbytes);
221 sFetchABL(abl, nbytes, buffers, 0, offset1);
222 nbytes += offset1;
223 }
224
225 int nchannels = abl->mNumberBuffers;
226 AudioBuffer *dest = abl->mBuffers;
227 while (--nchannels >= 0)
228 {
229 dest->mDataByteSize = nbytes;
230 dest++;
231 }
232
233 // now update the end time
234 MDRingBufferSetTimeBounds(ring, endRead, MDRingBufferEndTime(ring));
235
236 return kMDRingBufferError_OK;
237 }
238
239 int
240 MDRingBufferGetTimeBounds(MDRingBuffer *ring, MDSampleTime *startTime, MDSampleTime *endTime)
241 {
242 int i;
243 for (i = 0; i < 8; ++i) // fail after a few tries.
244 {
245 UInt32 curPtr = ring->timeBoundsQueuePtr;
246 UInt32 index = curPtr & kMDRingTimeBoundsQueueMask;
247 MDTimeBounds* bounds = ring->timeBoundsQueue + index;
248
249 *startTime = bounds->startTime;
250 *endTime = bounds->endTime;
251 UInt32 newPtr = bounds->updateCounter;
252
253 if (newPtr == curPtr)
254 return kMDRingBufferError_OK;
255 }
256 return kMDRingBufferError_CPUOverload;
257 }
258
259 int
260 MDRingBufferFrameOffset(MDRingBuffer *ring, MDSampleTime frameNumber)
261 {
262 return (int)((frameNumber & ring->capacityFramesMask) * ring->bytesPerFrame);
263 }
264
265 int
266 MDRingBufferCheckTimeBounds(MDRingBuffer *ring, MDSampleTime startRead, MDSampleTime endRead, bool aheadOK)
267 {
268 MDSampleTime startTime, endTime;
269
270 int err = MDRingBufferGetTimeBounds(ring, &startTime, &endTime);
271 if (err)
272 return err;
273
274 if (startRead < startTime)
275 {
276 if (endRead > endTime)
277 return kMDRingBufferError_TooMuch;
278
279 if (endRead < startTime)
280 return kMDRingBufferError_WayBehind;
281 else
282 return kMDRingBufferError_SlightlyBehind;
283 }
284
285 if (endRead > endTime) // we are going to read chunks of zeros its okay
286 {
287 if (aheadOK)
288 return kMDRingBufferError_OK;
289 else if (startRead > endTime)
290 return kMDRingBufferError_WayAhead;
291 else
292 return kMDRingBufferError_SlightlyAhead;
293 }
294
295 return kMDRingBufferError_OK; // success
296 }
297
298 MDSampleTime
299 MDRingBufferStartTime(MDRingBuffer *ring)
300 {
301 return ring->timeBoundsQueue[ring->timeBoundsQueuePtr & kMDRingTimeBoundsQueueMask].startTime;
302 }
303
304 MDSampleTime
305 MDRingBufferEndTime(MDRingBuffer *ring)
306 {
307 return ring->timeBoundsQueue[ring->timeBoundsQueuePtr & kMDRingTimeBoundsQueueMask].endTime;
308 }
309
310 void
311 MDRingBufferSetTimeBounds(MDRingBuffer *ring, MDSampleTime startTime, MDSampleTime endTime)
312 {
313 UInt32 nextPtr = ring->timeBoundsQueuePtr + 1;
314 UInt32 index = (nextPtr & kMDRingTimeBoundsQueueMask);
315
316 ring->timeBoundsQueue[index].startTime = startTime;
317 ring->timeBoundsQueue[index].endTime = endTime;
318 ring->timeBoundsQueue[index].updateCounter = nextPtr;
319
320 CompareAndSwap(ring->timeBoundsQueuePtr, ring->timeBoundsQueuePtr + 1, &ring->timeBoundsQueuePtr);
321 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26