1 /* 2 * Copyright 2001-2012 Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Christopher ML Zumwalt May (zummy@users.sf.net) 7 * Jérôme Duval 8 */ 9 10 11 #include <PushGameSound.h> 12 13 #include <List.h> 14 #include <string.h> 15 16 #include "GSUtility.h" 17 18 19 BPushGameSound::BPushGameSound(size_t inBufferFrameCount, 20 const gs_audio_format *format, size_t inBufferCount, 21 BGameSoundDevice *device) 22 : 23 BStreamingGameSound(inBufferFrameCount, format, inBufferCount, device), 24 fLockPos(0), 25 fPlayPos(0) 26 { 27 fPageLocked = new BList; 28 29 size_t frameSize = get_sample_size(format->format) * format->channel_count; 30 31 fPageCount = inBufferCount; 32 fPageSize = frameSize * inBufferFrameCount; 33 fBufferSize = fPageSize * fPageCount; 34 35 fBuffer = new char[fBufferSize]; 36 } 37 38 39 BPushGameSound::BPushGameSound(BGameSoundDevice * device) 40 : BStreamingGameSound(device), 41 fLockPos(0), 42 fPlayPos(0), 43 fBuffer(NULL), 44 fPageSize(0), 45 fPageCount(0), 46 fBufferSize(0) 47 { 48 fPageLocked = new BList; 49 } 50 51 52 BPushGameSound::~BPushGameSound() 53 { 54 delete [] fBuffer; 55 delete fPageLocked; 56 } 57 58 59 BPushGameSound::lock_status 60 BPushGameSound::LockNextPage(void **out_pagePtr, size_t *out_pageSize) 61 { 62 // the user can not lock every page 63 if (fPageLocked->CountItems() > fPageCount - 1) 64 return lock_failed; 65 66 // the user can't lock a page being played 67 if (fLockPos < fPlayPos 68 && fLockPos + fPageSize > fPlayPos) 69 return lock_failed; 70 71 // lock the page 72 char * lockPage = &fBuffer[fLockPos]; 73 fPageLocked->AddItem(lockPage); 74 75 // move the locker to the next page 76 fLockPos += fPageSize; 77 if (fLockPos >= fBufferSize) 78 fLockPos = 0; 79 80 *out_pagePtr = lockPage; 81 *out_pageSize = fPageSize; 82 83 return lock_ok; 84 } 85 86 87 status_t 88 BPushGameSound::UnlockPage(void *in_pagePtr) 89 { 90 return (fPageLocked->RemoveItem(in_pagePtr)) ? B_OK : B_ERROR; 91 } 92 93 94 BPushGameSound::lock_status 95 BPushGameSound::LockForCyclic(void **out_basePtr, size_t *out_size) 96 { 97 *out_basePtr = fBuffer; 98 *out_size = fBufferSize; 99 return lock_ok; 100 } 101 102 103 status_t 104 BPushGameSound::UnlockCyclic() 105 { 106 return B_OK; 107 } 108 109 110 size_t 111 BPushGameSound::CurrentPosition() 112 { 113 return fPlayPos; 114 } 115 116 117 BGameSound * 118 BPushGameSound::Clone() const 119 { 120 gs_audio_format format = Format(); 121 size_t frameSize = get_sample_size(format.format) * format.channel_count; 122 size_t bufferFrameCount = fPageSize / frameSize; 123 124 return new BPushGameSound(bufferFrameCount, &format, fPageCount, Device()); 125 } 126 127 128 status_t 129 BPushGameSound::Perform(int32 selector, void *data) 130 { 131 return BStreamingGameSound::Perform(selector, data); 132 } 133 134 135 status_t 136 BPushGameSound::SetParameters(size_t inBufferFrameCount, 137 const gs_audio_format *format, size_t inBufferCount) 138 { 139 return B_UNSUPPORTED; 140 } 141 142 143 status_t 144 BPushGameSound::SetStreamHook(void (*hook)(void * inCookie, void * inBuffer, 145 size_t inByteCount, BStreamingGameSound * me), void * cookie) 146 { 147 return B_UNSUPPORTED; 148 } 149 150 151 void 152 BPushGameSound::FillBuffer(void *inBuffer, size_t inByteCount) 153 { 154 size_t bytes = inByteCount; 155 156 if (!BytesReady(&bytes)) 157 return; 158 159 if (fPlayPos + bytes > fBufferSize) { 160 size_t remainder = fBufferSize - fPlayPos; 161 // Space left in buffer 162 char * buffer = (char*)inBuffer; 163 164 // fill the buffer with the samples left at the end of our buffer 165 memcpy(buffer, &fBuffer[fPlayPos], remainder); 166 fPlayPos = 0; 167 168 // fill the remainder of the buffer by looping to the start 169 // of the buffer if it isn't locked 170 bytes -= remainder; 171 if (BytesReady(&bytes)) { 172 memcpy(&buffer[remainder], fBuffer, bytes); 173 fPlayPos += bytes; 174 } 175 } else { 176 memcpy(inBuffer, &fBuffer[fPlayPos], bytes); 177 fPlayPos += bytes; 178 } 179 180 BStreamingGameSound::FillBuffer(inBuffer, inByteCount); 181 } 182 183 184 bool 185 BPushGameSound::BytesReady(size_t * bytes) 186 { 187 if (fPageLocked->CountItems() <= 0) 188 return true; 189 190 size_t start = fPlayPos; 191 size_t ready = fPlayPos; 192 int32 page = int32(start / fPageSize); 193 194 // return if there is nothing to do 195 if (fPageLocked->HasItem(&fBuffer[page * fPageSize])) 196 return false; 197 198 while (ready < *bytes) { 199 ready += fPageSize; 200 page = int32(ready / fPageSize); 201 202 if (fPageLocked->HasItem(&fBuffer[page * fPageSize])) { 203 // we have found a locked page 204 *bytes = ready - start - (ready - page * fPageSize); 205 return true; 206 } 207 } 208 209 // all of the bytes are ready 210 return true; 211 } 212 213 214 /* unimplemented for protection of the user: 215 * 216 * BPushGameSound::BPushGameSound() 217 * BPushGameSound::BPushGameSound(const BPushGameSound &) 218 * BPushGameSound &BPushGameSound::operator=(const BPushGameSound &) 219 */ 220 221 222 status_t 223 BPushGameSound::_Reserved_BPushGameSound_0(int32 arg, ...) 224 { 225 return B_ERROR; 226 } 227 228 229 status_t 230 BPushGameSound::_Reserved_BPushGameSound_1(int32 arg, ...) 231 { 232 return B_ERROR; 233 } 234 235 236 status_t 237 BPushGameSound::_Reserved_BPushGameSound_2(int32 arg, ...) 238 { 239 return B_ERROR; 240 } 241 242 243 status_t 244 BPushGameSound::_Reserved_BPushGameSound_3(int32 arg, ...) 245 { 246 return B_ERROR; 247 } 248 249 250 status_t 251 BPushGameSound::_Reserved_BPushGameSound_4(int32 arg, ...) 252 { 253 return B_ERROR; 254 } 255 256 257 status_t 258 BPushGameSound::_Reserved_BPushGameSound_5(int32 arg, ...) 259 { 260 return B_ERROR; 261 } 262 263 264 status_t 265 BPushGameSound::_Reserved_BPushGameSound_6(int32 arg, ...) 266 { 267 return B_ERROR; 268 } 269 270 271 status_t 272 BPushGameSound::_Reserved_BPushGameSound_7(int32 arg, ...) 273 { 274 return B_ERROR; 275 } 276 277 278 status_t 279 BPushGameSound::_Reserved_BPushGameSound_8(int32 arg, ...) 280 { 281 return B_ERROR; 282 } 283 284 285 status_t 286 BPushGameSound::_Reserved_BPushGameSound_9(int32 arg, ...) 287 { 288 return B_ERROR; 289 } 290 291 292 status_t 293 BPushGameSound::_Reserved_BPushGameSound_10(int32 arg, ...) 294 { 295 return B_ERROR; 296 } 297 298 299 status_t 300 BPushGameSound::_Reserved_BPushGameSound_11(int32 arg, ...) 301 { 302 return B_ERROR; 303 } 304 305 306 status_t 307 BPushGameSound::_Reserved_BPushGameSound_12(int32 arg, ...) 308 { 309 return B_ERROR; 310 } 311 312 313 status_t 314 BPushGameSound::_Reserved_BPushGameSound_13(int32 arg, ...) 315 { 316 return B_ERROR; 317 } 318 319 320 status_t 321 BPushGameSound::_Reserved_BPushGameSound_14(int32 arg, ...) 322 { 323 return B_ERROR; 324 } 325 326 327 status_t 328 BPushGameSound::_Reserved_BPushGameSound_15(int32 arg, ...) 329 { 330 return B_ERROR; 331 } 332 333 334 status_t 335 BPushGameSound::_Reserved_BPushGameSound_16(int32 arg, ...) 336 { 337 return B_ERROR; 338 } 339 340 341 status_t 342 BPushGameSound::_Reserved_BPushGameSound_17(int32 arg, ...) 343 { 344 return B_ERROR; 345 } 346 347 348 status_t 349 BPushGameSound::_Reserved_BPushGameSound_18(int32 arg, ...) 350 { 351 return B_ERROR; 352 } 353 354 355 status_t 356 BPushGameSound::_Reserved_BPushGameSound_19(int32 arg, ...) 357 { 358 return B_ERROR; 359 } 360 361 362 status_t 363 BPushGameSound::_Reserved_BPushGameSound_20(int32 arg, ...) 364 { 365 return B_ERROR; 366 } 367 368 369 status_t 370 BPushGameSound::_Reserved_BPushGameSound_21(int32 arg, ...) 371 { 372 return B_ERROR; 373 } 374 375 376 status_t 377 BPushGameSound::_Reserved_BPushGameSound_22(int32 arg, ...) 378 { 379 return B_ERROR; 380 } 381 382 383 status_t 384 BPushGameSound::_Reserved_BPushGameSound_23(int32 arg, ...) 385 { 386 return B_ERROR; 387 } 388