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