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 <stdlib.h> 11 #include <string.h> 12 13 #include <Entry.h> 14 #include <FileGameSound.h> 15 #include <MediaFile.h> 16 #include <MediaTrack.h> 17 #include <scheduler.h> 18 19 #include "GameSoundDevice.h" 20 #include "GSUtility.h" 21 22 const int32 kPages = 20; 23 struct _gs_media_tracker 24 { 25 BMediaFile * file; 26 BMediaTrack * stream; 27 int64 frames; 28 size_t position; 29 }; 30 31 // Locale utility functions ----------------------------------------------- 32 bool FillBuffer(_gs_ramp * ramp, uint8 * data, uint8 * buffer, size_t * bytes) 33 { 34 int32 samples = *bytes / sizeof(int16); 35 36 for(int32 byte = 0; byte < samples; byte++) 37 { 38 float gain = *ramp->value; 39 data[byte] = uint8(float(buffer[byte]) * gain); 40 41 if (ChangeRamp(ramp)) 42 { 43 *bytes = byte * sizeof(int16); 44 return true; 45 } 46 } 47 48 return false; 49 } 50 51 bool FillBuffer(_gs_ramp * ramp, int16 * data, int16 * buffer, size_t * bytes) 52 { 53 int32 samples = *bytes / sizeof(int16); 54 55 for(int32 byte = 0; byte < samples; byte++) 56 { 57 float gain = *ramp->value; 58 data[byte] = int16(float(buffer[byte]) * gain); 59 60 if (ChangeRamp(ramp)) 61 { 62 *bytes = byte * sizeof(int16); 63 return true; 64 } 65 } 66 67 return false; 68 } 69 70 bool FillBuffer(_gs_ramp * ramp, int32 * data, int32 * buffer, size_t * bytes) 71 { 72 size_t byte = 0; 73 bool bytesAreReady = (*bytes > 0); 74 75 while(bytesAreReady) 76 { 77 float gain = *ramp->value; 78 data[byte] = int32(float(buffer[byte]) * gain); 79 80 if (ChangeRamp(ramp)) 81 { 82 *bytes = byte; 83 return true; 84 } 85 86 byte++; 87 bytesAreReady = (byte >= *bytes); 88 } 89 90 return false; 91 } 92 93 bool FillBuffer(_gs_ramp * ramp, float * data, float * buffer, size_t * bytes) 94 { 95 size_t byte = 0; 96 bool bytesAreReady = (*bytes > 0); 97 98 while(bytesAreReady) 99 { 100 float gain = *ramp->value; 101 data[byte] = buffer[byte] * gain; 102 103 if (ChangeRamp(ramp)) 104 { 105 *bytes = byte; 106 return true; 107 } 108 109 byte++; 110 bytesAreReady = (byte >= *bytes); 111 } 112 113 return false; 114 } 115 116 // BFileGameSound ------------------------------------------------------- 117 BFileGameSound::BFileGameSound(const entry_ref *file, 118 bool looping, 119 BGameSoundDevice *device) 120 : BStreamingGameSound(device), 121 fAudioStream(NULL), 122 fStopping(false), 123 fLooping(looping), 124 fBuffer(NULL), 125 fPlayPosition(0), 126 fPausing(NULL), 127 fPaused(false), 128 fPauseGain(1.0) 129 { 130 if (InitCheck() == B_OK) 131 SetInitError(Init(file)); 132 } 133 134 135 BFileGameSound::BFileGameSound(const char *file, 136 bool looping, 137 BGameSoundDevice *device) 138 : BStreamingGameSound(device), 139 fAudioStream(NULL), 140 fStopping(false), 141 fLooping(looping), 142 fBuffer(NULL), 143 fPlayPosition(0), 144 fPausing(NULL), 145 fPaused(false), 146 fPauseGain(1.0) 147 { 148 if (InitCheck() == B_OK) 149 { 150 entry_ref node; 151 152 if (get_ref_for_path(file, &node) != B_OK) 153 SetInitError(B_ENTRY_NOT_FOUND); 154 else 155 SetInitError(Init(&node)); 156 } 157 } 158 159 160 BFileGameSound::~BFileGameSound() 161 { 162 if (fReadThread >= 0) kill_thread(fReadThread); 163 164 if (fAudioStream) 165 { 166 if (fAudioStream->stream) 167 fAudioStream->file->ReleaseTrack(fAudioStream->stream); 168 169 delete fAudioStream->file; 170 } 171 172 delete [] fBuffer; 173 delete fAudioStream; 174 } 175 176 177 BGameSound * 178 BFileGameSound::Clone() const 179 { 180 return NULL; 181 } 182 183 184 status_t 185 BFileGameSound::StartPlaying() 186 { 187 // restart playback if needed 188 if (IsPlaying()) 189 StopPlaying(); 190 191 // start playing the file 192 return BStreamingGameSound::StartPlaying(); 193 } 194 195 196 status_t 197 BFileGameSound::StopPlaying() 198 { 199 status_t error = BStreamingGameSound::StopPlaying(); 200 201 // start reading next time from the start of the file 202 int64 frame = 0; 203 fAudioStream->stream->SeekToFrame(&frame); 204 205 fStopping = false; 206 fAudioStream->position = 0; 207 fPlayPosition = 0; 208 209 return error; 210 } 211 212 213 status_t 214 BFileGameSound::Preload() 215 { 216 if (!IsPlaying()) 217 Load(); 218 219 return B_OK; 220 } 221 222 223 void 224 BFileGameSound::FillBuffer(void *inBuffer, 225 size_t inByteCount) 226 { 227 size_t bytes = inByteCount; 228 229 if (!fPaused || fPausing) { 230 if (fPlayPosition == 0 || fPlayPosition + inByteCount >= fBufferSize) { 231 Load(); 232 } 233 234 if (fPausing) { 235 Lock(); 236 237 bool rampDone = false; 238 239 // Fill the requested buffer, stopping if the paused flag is set 240 switch(Format().format) { 241 case gs_audio_format::B_GS_U8: 242 rampDone = ::FillBuffer(fPausing, (uint8*)inBuffer, (uint8*)&fBuffer[fPlayPosition], &bytes); 243 break; 244 245 case gs_audio_format::B_GS_S16: 246 rampDone = ::FillBuffer(fPausing, (int16*)inBuffer, (int16*)&fBuffer[fPlayPosition], &bytes); 247 break; 248 249 case gs_audio_format::B_GS_S32: 250 rampDone = ::FillBuffer(fPausing, (int32*)inBuffer, (int32*)&fBuffer[fPlayPosition], &bytes); 251 break; 252 253 case gs_audio_format::B_GS_F: 254 rampDone = ::FillBuffer(fPausing, (float*)inBuffer, (float*)&fBuffer[fPlayPosition], &bytes); 255 break; 256 } 257 258 // We finished ramping 259 if (rampDone) { 260 if (bytes < inByteCount && !fPausing) { 261 // Since we are resuming play back, we need to copy any remaining samples 262 char * buffer = (char*)inBuffer; 263 memcpy(&buffer[bytes], &fBuffer[fPlayPosition + bytes], inByteCount - bytes); 264 } 265 266 delete fPausing; 267 fPausing = NULL; 268 } 269 270 Unlock(); 271 } else { 272 size_t byte = 0; 273 char * buffer = (char*)inBuffer; 274 275 // We need to be able to stop asap when the pause flag is flipped. 276 while(byte < bytes && (!fPaused || fPausing)) { 277 buffer[byte] = fBuffer[fPlayPosition + byte]; 278 byte++; 279 } 280 281 bytes = byte; 282 } 283 } 284 285 fPlayPosition += bytes; 286 } 287 288 289 status_t 290 BFileGameSound::Perform(int32 selector, 291 void *data) 292 { 293 return B_ERROR; 294 } 295 296 297 status_t 298 BFileGameSound::SetPaused(bool isPaused, 299 bigtime_t rampTime) 300 { 301 if (fPaused != isPaused) 302 { 303 Lock(); 304 305 // Clear any old ramping 306 delete fPausing; 307 fPausing = NULL; 308 309 if (rampTime > 100000) 310 { 311 // Setup for ramping 312 if (isPaused) 313 fPausing = InitRamp(&fPauseGain, 0.0, Format().frame_rate, rampTime); 314 else 315 fPausing = InitRamp(&fPauseGain, 1.0, Format().frame_rate, rampTime); 316 } 317 318 fPaused = isPaused; 319 Unlock(); 320 } 321 322 return B_OK; 323 } 324 325 326 int32 327 BFileGameSound::IsPaused() 328 { 329 if (fPausing) return B_PAUSE_IN_PROGRESS; 330 331 if (fPaused) return B_PAUSED; 332 333 return B_NOT_PAUSED; 334 } 335 336 337 status_t 338 BFileGameSound::Init(const entry_ref* file) 339 { 340 fAudioStream = new _gs_media_tracker; 341 memset(fAudioStream, 0, sizeof(_gs_media_tracker)); 342 343 fAudioStream->file = new BMediaFile(file); 344 status_t error = fAudioStream->file->InitCheck(); 345 if (error != B_OK) 346 return error; 347 348 fAudioStream->stream = fAudioStream->file->TrackAt(0); 349 350 // is this is an audio file? 351 media_format playFormat; 352 fAudioStream->stream->EncodedFormat(&playFormat); 353 if (!playFormat.IsAudio()) 354 return B_MEDIA_BAD_FORMAT; 355 356 gs_audio_format dformat = Device()->Format(); 357 358 // request the format we want the sound 359 memset(&playFormat, 0, sizeof(media_format)); 360 playFormat.type = B_MEDIA_RAW_AUDIO; 361 if (fAudioStream->stream->DecodedFormat(&playFormat) != B_OK) 362 return B_MEDIA_BAD_FORMAT; 363 364 // translate the format into a "GameKit" friendly one 365 gs_audio_format gsformat; 366 media_to_gs_format(&gsformat, &playFormat.u.raw_audio); 367 368 // Since the buffer sized read from the file is most likely differnt 369 // then the buffer used by the audio mixer, we must allocate a buffer 370 // large enough to hold the largest request. 371 fBufferSize = gsformat.buffer_size; 372 if (fBufferSize < dformat.buffer_size) 373 fBufferSize = dformat.buffer_size; 374 375 // create the buffer 376 fBuffer = new char[fBufferSize * 2]; 377 memset(fBuffer, 0, fBufferSize * 2); 378 379 fFrameSize = gsformat.channel_count * get_sample_size(gsformat.format); 380 fAudioStream->frames = fAudioStream->stream->CountFrames(); 381 382 // Ask the device to attach our sound to it 383 gs_id sound; 384 error = Device()->CreateBuffer(&sound, this, &gsformat); 385 if (error != B_OK) 386 return error; 387 388 return BGameSound::Init(sound); 389 } 390 391 392 bool 393 BFileGameSound::Load() 394 { 395 396 if (fPlayPosition != 0) { 397 memcpy(fBuffer, fBuffer + fPlayPosition, fBufferSize - fPlayPosition); 398 fPlayPosition = fBufferSize - fPlayPosition; 399 } 400 401 // time to read a new buffer 402 int64 frames = 0; 403 fAudioStream->stream->ReadFrames(fBuffer + fPlayPosition, &frames); 404 fBufferSize = fPlayPosition + frames * fFrameSize; 405 fPlayPosition = 0; 406 407 return true; 408 } 409 410 411 bool 412 BFileGameSound::Read(void * buffer, size_t bytes) 413 { 414 return false; 415 } 416 417 418 /* unimplemented for protection of the user: 419 * 420 * BFileGameSound::BFileGameSound() 421 * BFileGameSound::BFileGameSound(const BFileGameSound &) 422 * BFileGameSound &BFileGameSound::operator=(const BFileGameSound &) 423 */ 424 425 426 status_t 427 BFileGameSound::_Reserved_BFileGameSound_0(int32 arg, ...) 428 { 429 return B_ERROR; 430 } 431 432 433 status_t 434 BFileGameSound::_Reserved_BFileGameSound_1(int32 arg, ...) 435 { 436 return B_ERROR; 437 } 438 439 440 status_t 441 BFileGameSound::_Reserved_BFileGameSound_2(int32 arg, ...) 442 { 443 return B_ERROR; 444 } 445 446 447 status_t 448 BFileGameSound::_Reserved_BFileGameSound_3(int32 arg, ...) 449 { 450 return B_ERROR; 451 } 452 453 454 status_t 455 BFileGameSound::_Reserved_BFileGameSound_4(int32 arg, ...) 456 { 457 return B_ERROR; 458 } 459 460 461 status_t 462 BFileGameSound::_Reserved_BFileGameSound_5(int32 arg, ...) 463 { 464 return B_ERROR; 465 } 466 467 468 status_t 469 BFileGameSound::_Reserved_BFileGameSound_6(int32 arg, ...) 470 { 471 return B_ERROR; 472 } 473 474 475 status_t 476 BFileGameSound::_Reserved_BFileGameSound_7(int32 arg, ...) 477 { 478 return B_ERROR; 479 } 480 481 482 status_t 483 BFileGameSound::_Reserved_BFileGameSound_8(int32 arg, ...) 484 { 485 return B_ERROR; 486 } 487 488 489 status_t 490 BFileGameSound::_Reserved_BFileGameSound_9(int32 arg, ...) 491 { 492 return B_ERROR; 493 } 494 495 496 status_t 497 BFileGameSound::_Reserved_BFileGameSound_10(int32 arg, ...) 498 { 499 return B_ERROR; 500 } 501 502 503 status_t 504 BFileGameSound::_Reserved_BFileGameSound_11(int32 arg, ...) 505 { 506 return B_ERROR; 507 } 508 509 510 status_t 511 BFileGameSound::_Reserved_BFileGameSound_12(int32 arg, ...) 512 { 513 return B_ERROR; 514 } 515 516 517 status_t 518 BFileGameSound::_Reserved_BFileGameSound_13(int32 arg, ...) 519 { 520 return B_ERROR; 521 } 522 523 524 status_t 525 BFileGameSound::_Reserved_BFileGameSound_14(int32 arg, ...) 526 { 527 return B_ERROR; 528 } 529 530 531 status_t 532 BFileGameSound::_Reserved_BFileGameSound_15(int32 arg, ...) 533 { 534 return B_ERROR; 535 } 536 537 538 status_t 539 BFileGameSound::_Reserved_BFileGameSound_16(int32 arg, ...) 540 { 541 return B_ERROR; 542 } 543 544 545 status_t 546 BFileGameSound::_Reserved_BFileGameSound_17(int32 arg, ...) 547 { 548 return B_ERROR; 549 } 550 551 552 status_t 553 BFileGameSound::_Reserved_BFileGameSound_18(int32 arg, ...) 554 { 555 return B_ERROR; 556 } 557 558 559 status_t 560 BFileGameSound::_Reserved_BFileGameSound_19(int32 arg, ...) 561 { 562 return B_ERROR; 563 } 564 565 566 status_t 567 BFileGameSound::_Reserved_BFileGameSound_20(int32 arg, ...) 568 { 569 return B_ERROR; 570 } 571 572 573 status_t 574 BFileGameSound::_Reserved_BFileGameSound_21(int32 arg, ...) 575 { 576 return B_ERROR; 577 } 578 579 580 status_t 581 BFileGameSound::_Reserved_BFileGameSound_22(int32 arg, ...) 582 { 583 return B_ERROR; 584 } 585 586 587 status_t 588 BFileGameSound::_Reserved_BFileGameSound_23(int32 arg, ...) 589 { 590 return B_ERROR; 591 } 592 593 594