/libs/ObjectAL/OpenAL/ALSource.m

http://github.com/kstenerud/ObjectAL-for-iPhone · Objective C · 1315 lines · 1072 code · 190 blank · 53 comment · 104 complexity · 117557c0304ae421211838b55dc30765 MD5 · raw file

  1. //
  2. // ALSource.m
  3. // ObjectAL
  4. //
  5. // Created by Karl Stenerud on 15/12/09.
  6. //
  7. // Copyright 2009 Karl Stenerud
  8. //
  9. // Licensed under the Apache License, Version 2.0 (the "License");
  10. // you may not use this file except in compliance with the License.
  11. // You may obtain a copy of the License at
  12. //
  13. // http://www.apache.org/licenses/LICENSE-2.0
  14. //
  15. // Unless required by applicable law or agreed to in writing, software
  16. // distributed under the License is distributed on an "AS IS" BASIS,
  17. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. // See the License for the specific language governing permissions and
  19. // limitations under the License.
  20. //
  21. // Note: You are NOT required to make the license available from within your
  22. // iOS application. Including it in your project is sufficient.
  23. //
  24. // Attribution is not required, but appreciated :)
  25. //
  26. #import "ALSource.h"
  27. #import "ObjectALMacros.h"
  28. #import "ALWrapper.h"
  29. #import "OpenALManager.h"
  30. #import "OALAudioActions.h"
  31. #import "OALUtilityActions.h"
  32. #pragma mark -
  33. #pragma mark Private Methods
  34. /**
  35. * (INTERNAL USE) Private methods for ALSource.
  36. */
  37. @interface ALSource (Private)
  38. /** (INTERNAL USE) Close any resources belonging to the OS.
  39. */
  40. - (void) closeOSResources;
  41. /** (INTERNAL USE) Called by SuspendHandler.
  42. */
  43. - (void) setSuspended:(bool) value;
  44. /** (INTERNAL USE) Callback for resuming playback after delay to
  45. * get around OpenAL bug.
  46. */
  47. - (void) delayedResumePlayback;
  48. @end
  49. @implementation ALSource
  50. #pragma mark Object Management
  51. + (id) source
  52. {
  53. return [[[self alloc] init] autorelease];
  54. }
  55. + (id) sourceOnContext:(ALContext*) context
  56. {
  57. return [[[self alloc] initOnContext:context] autorelease];
  58. }
  59. - (id) init
  60. {
  61. return [self initOnContext:[OpenALManager sharedInstance].currentContext];
  62. }
  63. - (id) initOnContext:(ALContext*) contextIn
  64. {
  65. if(nil != (self = [super init]))
  66. {
  67. OAL_LOG_DEBUG(@"%@: Init on context %@", self, contextIn);
  68. if(nil == contextIn)
  69. {
  70. OAL_LOG_ERROR(@"%@: Failed to init because context was nil. Returning nil", self);
  71. [self release];
  72. return nil;
  73. }
  74. suspendHandler = [[OALSuspendHandler alloc] initWithTarget:self selector:@selector(setSuspended:)];
  75. context = [contextIn retain];
  76. @synchronized([OpenALManager sharedInstance])
  77. {
  78. ALContext* realContext = [OpenALManager sharedInstance].currentContext;
  79. [OpenALManager sharedInstance].currentContext = context;
  80. sourceId = [ALWrapper genSource];
  81. [OpenALManager sharedInstance].currentContext = realContext;
  82. }
  83. OAL_LOG_DEBUG(@"%@: Created source %08x", self, sourceId);
  84. [context notifySourceInitializing:self];
  85. gain = [ALWrapper getSourcef:sourceId parameter:AL_GAIN];
  86. shadowState = AL_INITIAL;
  87. [context addSuspendListener:self];
  88. }
  89. return self;
  90. }
  91. - (void) dealloc
  92. {
  93. OAL_LOG_DEBUG(@"%@: Dealloc, sourceId = %08x", self, sourceId);
  94. [context removeSuspendListener:self];
  95. [context notifySourceDeallocating:self];
  96. [self closeOSResources];
  97. [gainAction stopAction];
  98. [gainAction release];
  99. [panAction stopAction];
  100. [panAction release];
  101. [pitchAction stopAction];
  102. [pitchAction release];
  103. [suspendHandler release];
  104. [context release];
  105. // In IOS 3.x, OpenAL doesn't stop playing right away.
  106. // Release after a delay to give it some time to stop.
  107. [buffer performSelector:@selector(release) withObject:nil afterDelay:0.1];
  108. [super dealloc];
  109. }
  110. - (void) closeOSResources
  111. {
  112. OPTIONALLY_SYNCHRONIZED(self)
  113. {
  114. if((ALuint)AL_INVALID != sourceId)
  115. {
  116. [ALWrapper sourceStop:sourceId];
  117. [ALWrapper sourcei:sourceId parameter:AL_BUFFER value:AL_NONE];
  118. @synchronized([OpenALManager sharedInstance])
  119. {
  120. ALContext* realContext = [OpenALManager sharedInstance].currentContext;
  121. if(realContext != context)
  122. {
  123. // Make this source's context the current one if it isn't already.
  124. [OpenALManager sharedInstance].currentContext = context;
  125. }
  126. [ALWrapper deleteSource:sourceId];
  127. [OpenALManager sharedInstance].currentContext = realContext;
  128. }
  129. sourceId = (ALuint)AL_INVALID;
  130. }
  131. }
  132. }
  133. - (void) close
  134. {
  135. [self closeOSResources];
  136. }
  137. #pragma mark Properties
  138. - (ALBuffer*) buffer
  139. {
  140. OPTIONALLY_SYNCHRONIZED(self)
  141. {
  142. return buffer;
  143. }
  144. }
  145. - (void) setBuffer:(ALBuffer *) value
  146. {
  147. OPTIONALLY_SYNCHRONIZED(self)
  148. {
  149. if(self.suspended)
  150. {
  151. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  152. return;
  153. }
  154. [self stop];
  155. // In IOS 3.x, OpenAL doesn't stop playing right away.
  156. // Release after a delay to give it some time to stop.
  157. [buffer performSelector:@selector(release) withObject:nil afterDelay:0.1];
  158. buffer = [value retain];
  159. [ALWrapper sourcei:sourceId parameter:AL_BUFFER value:buffer.bufferId];
  160. }
  161. }
  162. - (int) buffersQueued
  163. {
  164. return [ALWrapper getSourcei:sourceId parameter:AL_BUFFERS_QUEUED];
  165. }
  166. - (int) buffersProcessed
  167. {
  168. return [ALWrapper getSourcei:sourceId parameter:AL_BUFFERS_PROCESSED];
  169. }
  170. - (float) coneInnerAngle
  171. {
  172. OPTIONALLY_SYNCHRONIZED(self)
  173. {
  174. return [ALWrapper getSourcef:sourceId parameter:AL_CONE_INNER_ANGLE];
  175. }
  176. }
  177. - (void) setConeInnerAngle:(float) value
  178. {
  179. OPTIONALLY_SYNCHRONIZED(self)
  180. {
  181. if(self.suspended)
  182. {
  183. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  184. return;
  185. }
  186. [ALWrapper sourcef:sourceId parameter:AL_CONE_INNER_ANGLE value:value];
  187. }
  188. }
  189. - (float) coneOuterAngle
  190. {
  191. OPTIONALLY_SYNCHRONIZED(self)
  192. {
  193. return [ALWrapper getSourcef:sourceId parameter:AL_CONE_OUTER_ANGLE];
  194. }
  195. }
  196. - (void) setConeOuterAngle:(float) value
  197. {
  198. OPTIONALLY_SYNCHRONIZED(self)
  199. {
  200. if(self.suspended)
  201. {
  202. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  203. return;
  204. }
  205. [ALWrapper sourcef:sourceId parameter:AL_CONE_OUTER_ANGLE value:value];
  206. }
  207. }
  208. - (float) coneOuterGain
  209. {
  210. OPTIONALLY_SYNCHRONIZED(self)
  211. {
  212. return [ALWrapper getSourcef:sourceId parameter:AL_CONE_OUTER_GAIN];
  213. }
  214. }
  215. - (void) setConeOuterGain:(float) value
  216. {
  217. OPTIONALLY_SYNCHRONIZED(self)
  218. {
  219. if(self.suspended)
  220. {
  221. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  222. return;
  223. }
  224. [ALWrapper sourcef:sourceId parameter:AL_CONE_OUTER_GAIN value:value];
  225. }
  226. }
  227. @synthesize context;
  228. - (ALVector) direction
  229. {
  230. ALVector result;
  231. OPTIONALLY_SYNCHRONIZED(self)
  232. {
  233. [ALWrapper getSource3f:sourceId parameter:AL_DIRECTION v1:&result.x v2:&result.y v3:&result.z];
  234. }
  235. return result;
  236. }
  237. - (void) setDirection:(ALVector) value
  238. {
  239. OPTIONALLY_SYNCHRONIZED(self)
  240. {
  241. if(self.suspended)
  242. {
  243. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  244. return;
  245. }
  246. [ALWrapper source3f:sourceId parameter:AL_DIRECTION v1:value.x v2:value.y v3:value.z];
  247. }
  248. }
  249. - (float) volume
  250. {
  251. return self.gain;
  252. }
  253. - (void) setVolume:(float) value
  254. {
  255. self.gain = value;
  256. }
  257. - (float) gain
  258. {
  259. OPTIONALLY_SYNCHRONIZED(self)
  260. {
  261. return gain;
  262. }
  263. }
  264. - (void) setGain:(float) value
  265. {
  266. OPTIONALLY_SYNCHRONIZED(self)
  267. {
  268. if(self.suspended)
  269. {
  270. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  271. return;
  272. }
  273. gain = value;
  274. if(muted)
  275. {
  276. value = 0;
  277. }
  278. [ALWrapper sourcef:sourceId parameter:AL_GAIN value:value];
  279. }
  280. }
  281. @synthesize interruptible;
  282. - (bool) looping
  283. {
  284. OPTIONALLY_SYNCHRONIZED(self)
  285. {
  286. return [ALWrapper getSourcei:sourceId parameter:AL_LOOPING];
  287. }
  288. }
  289. - (void) setLooping:(bool) value
  290. {
  291. OPTIONALLY_SYNCHRONIZED(self)
  292. {
  293. if(self.suspended)
  294. {
  295. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  296. return;
  297. }
  298. [ALWrapper sourcei:sourceId parameter:AL_LOOPING value:value];
  299. }
  300. }
  301. - (float) maxDistance
  302. {
  303. OPTIONALLY_SYNCHRONIZED(self)
  304. {
  305. return [ALWrapper getSourcef:sourceId parameter:AL_MAX_DISTANCE];
  306. }
  307. }
  308. - (void) setMaxDistance:(float) value
  309. {
  310. OPTIONALLY_SYNCHRONIZED(self)
  311. {
  312. if(self.suspended)
  313. {
  314. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  315. return;
  316. }
  317. [ALWrapper sourcef:sourceId parameter:AL_MAX_DISTANCE value:value];
  318. }
  319. }
  320. - (float) maxGain
  321. {
  322. OPTIONALLY_SYNCHRONIZED(self)
  323. {
  324. return [ALWrapper getSourcef:sourceId parameter:AL_MAX_GAIN];
  325. }
  326. }
  327. - (void) setMaxGain:(float) value
  328. {
  329. OPTIONALLY_SYNCHRONIZED(self)
  330. {
  331. if(self.suspended)
  332. {
  333. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  334. return;
  335. }
  336. [ALWrapper sourcef:sourceId parameter:AL_MAX_GAIN value:value];
  337. }
  338. }
  339. - (float) minGain
  340. {
  341. OPTIONALLY_SYNCHRONIZED(self)
  342. {
  343. return [ALWrapper getSourcef:sourceId parameter:AL_MIN_GAIN];
  344. }
  345. }
  346. - (void) setMinGain:(float) value
  347. {
  348. OPTIONALLY_SYNCHRONIZED(self)
  349. {
  350. if(self.suspended)
  351. {
  352. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  353. return;
  354. }
  355. [ALWrapper sourcef:sourceId parameter:AL_MIN_GAIN value:value];
  356. }
  357. }
  358. - (bool) muted
  359. {
  360. OPTIONALLY_SYNCHRONIZED(self)
  361. {
  362. return muted;
  363. }
  364. }
  365. - (void) setMuted:(bool) value
  366. {
  367. OPTIONALLY_SYNCHRONIZED(self)
  368. {
  369. if(self.suspended)
  370. {
  371. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  372. return;
  373. }
  374. muted = value;
  375. if(muted)
  376. {
  377. [self stopActions];
  378. }
  379. // Force a re-evaluation of gain.
  380. [self setGain:gain];
  381. }
  382. }
  383. - (float) offsetInBytes
  384. {
  385. OPTIONALLY_SYNCHRONIZED(self)
  386. {
  387. return [ALWrapper getSourcef:sourceId parameter:AL_BYTE_OFFSET];
  388. }
  389. }
  390. - (void) setOffsetInBytes:(float) value
  391. {
  392. OPTIONALLY_SYNCHRONIZED(self)
  393. {
  394. if(self.suspended)
  395. {
  396. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  397. return;
  398. }
  399. [ALWrapper sourcef:sourceId parameter:AL_BYTE_OFFSET value:value];
  400. }
  401. }
  402. - (float) offsetInSamples
  403. {
  404. OPTIONALLY_SYNCHRONIZED(self)
  405. {
  406. return [ALWrapper getSourcef:sourceId parameter:AL_SAMPLE_OFFSET];
  407. }
  408. }
  409. - (void) setOffsetInSamples:(float) value
  410. {
  411. OPTIONALLY_SYNCHRONIZED(self)
  412. {
  413. if(self.suspended)
  414. {
  415. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  416. return;
  417. }
  418. [ALWrapper sourcef:sourceId parameter:AL_SAMPLE_OFFSET value:value];
  419. }
  420. }
  421. - (float) offsetInSeconds
  422. {
  423. OPTIONALLY_SYNCHRONIZED(self)
  424. {
  425. return [ALWrapper getSourcef:sourceId parameter:AL_SEC_OFFSET];
  426. }
  427. }
  428. - (void) setOffsetInSeconds:(float) value
  429. {
  430. OPTIONALLY_SYNCHRONIZED(self)
  431. {
  432. if(self.suspended)
  433. {
  434. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  435. return;
  436. }
  437. [ALWrapper sourcef:sourceId parameter:AL_SEC_OFFSET value:value];
  438. }
  439. }
  440. - (bool) paused
  441. {
  442. if(self.suspended)
  443. {
  444. return AL_PAUSED == shadowState;
  445. }
  446. return AL_PAUSED == self.state;
  447. }
  448. - (void) setPaused:(bool) shouldPause
  449. {
  450. OPTIONALLY_SYNCHRONIZED(self)
  451. {
  452. if(self.suspended)
  453. {
  454. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  455. return;
  456. }
  457. if(shouldPause)
  458. {
  459. if(AL_PLAYING == self.state)
  460. {
  461. abortPlaybackResume = YES;
  462. if([ALWrapper sourcePause:sourceId])
  463. {
  464. shadowState = AL_PAUSED;
  465. }
  466. }
  467. }
  468. else
  469. {
  470. if(AL_PAUSED == self.state)
  471. {
  472. if([ALWrapper sourcePlay:sourceId])
  473. {
  474. shadowState = AL_PLAYING;
  475. }
  476. else
  477. {
  478. shadowState = AL_STOPPED;
  479. }
  480. }
  481. }
  482. }
  483. }
  484. - (float) pitch
  485. {
  486. OPTIONALLY_SYNCHRONIZED(self)
  487. {
  488. return [ALWrapper getSourcef:sourceId parameter:AL_PITCH];
  489. }
  490. }
  491. - (void) setPitch:(float) value
  492. {
  493. OPTIONALLY_SYNCHRONIZED(self)
  494. {
  495. if(self.suspended)
  496. {
  497. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  498. return;
  499. }
  500. [ALWrapper sourcef:sourceId parameter:AL_PITCH value:value];
  501. }
  502. }
  503. - (bool) playing
  504. {
  505. if(self.suspended)
  506. {
  507. return AL_PLAYING == shadowState || AL_PAUSED == shadowState;
  508. }
  509. return AL_PLAYING == self.state || AL_PAUSED == self.state;
  510. }
  511. - (ALPoint) position
  512. {
  513. ALPoint result;
  514. OPTIONALLY_SYNCHRONIZED(self)
  515. {
  516. [ALWrapper getSource3f:sourceId parameter:AL_POSITION v1:&result.x v2:&result.y v3:&result.z];
  517. }
  518. return result;
  519. }
  520. - (void) setPosition:(ALPoint) value
  521. {
  522. OPTIONALLY_SYNCHRONIZED(self)
  523. {
  524. if(self.suspended)
  525. {
  526. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  527. return;
  528. }
  529. [ALWrapper source3f:sourceId parameter:AL_POSITION v1:value.x v2:value.y v3:value.z];
  530. }
  531. }
  532. - (float) pan
  533. {
  534. return self.position.x;
  535. }
  536. - (void) setPan:(float) value
  537. {
  538. if(self.suspended)
  539. {
  540. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  541. return;
  542. }
  543. self.position = alpoint(value, 0, 0);
  544. }
  545. - (float) referenceDistance
  546. {
  547. OPTIONALLY_SYNCHRONIZED(self)
  548. {
  549. return [ALWrapper getSourcef:sourceId parameter:AL_REFERENCE_DISTANCE];
  550. }
  551. }
  552. - (void) setReferenceDistance:(float) value
  553. {
  554. OPTIONALLY_SYNCHRONIZED(self)
  555. {
  556. if(self.suspended)
  557. {
  558. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  559. return;
  560. }
  561. [ALWrapper sourcef:sourceId parameter:AL_REFERENCE_DISTANCE value:value];
  562. }
  563. }
  564. - (float) rolloffFactor
  565. {
  566. OPTIONALLY_SYNCHRONIZED(self)
  567. {
  568. return [ALWrapper getSourcef:sourceId parameter:AL_ROLLOFF_FACTOR];
  569. }
  570. }
  571. - (void) setRolloffFactor:(float) value
  572. {
  573. OPTIONALLY_SYNCHRONIZED(self)
  574. {
  575. if(self.suspended)
  576. {
  577. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  578. return;
  579. }
  580. [ALWrapper sourcef:sourceId parameter:AL_ROLLOFF_FACTOR value:value];
  581. }
  582. }
  583. @synthesize sourceId;
  584. - (int) sourceRelative
  585. {
  586. OPTIONALLY_SYNCHRONIZED(self)
  587. {
  588. return [ALWrapper getSourcei:sourceId parameter:AL_SOURCE_RELATIVE];
  589. }
  590. }
  591. - (void) setSourceRelative:(int) value
  592. {
  593. OPTIONALLY_SYNCHRONIZED(self)
  594. {
  595. if(self.suspended)
  596. {
  597. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  598. return;
  599. }
  600. [ALWrapper sourcei:sourceId parameter:AL_SOURCE_RELATIVE value:value];
  601. }
  602. }
  603. - (int) sourceType
  604. {
  605. OPTIONALLY_SYNCHRONIZED(self)
  606. {
  607. return [ALWrapper getSourcei:sourceId parameter:AL_SOURCE_TYPE];
  608. }
  609. }
  610. - (void) setSourceType:(int) value
  611. {
  612. OPTIONALLY_SYNCHRONIZED(self)
  613. {
  614. if(self.suspended)
  615. {
  616. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  617. return;
  618. }
  619. [ALWrapper sourcei:sourceId parameter:AL_SOURCE_TYPE value:value];
  620. }
  621. }
  622. - (int) state
  623. {
  624. OPTIONALLY_SYNCHRONIZED(self)
  625. {
  626. // Apple's OpenAL implementation is broken.
  627. //return [ALWrapper getSourcei:sourceId parameter:AL_SOURCE_STATE];
  628. if(AL_INITIAL == shadowState || AL_STOPPED == shadowState)
  629. {
  630. return shadowState;
  631. }
  632. if(AL_STOPPED == [ALWrapper getSourcei:sourceId parameter:AL_SOURCE_STATE])
  633. {
  634. return AL_STOPPED;
  635. }
  636. return shadowState;
  637. }
  638. }
  639. - (void) setState:(int) value
  640. {
  641. OPTIONALLY_SYNCHRONIZED(self)
  642. {
  643. if(self.suspended)
  644. {
  645. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  646. return;
  647. }
  648. [ALWrapper sourcei:sourceId parameter:AL_SOURCE_STATE value:value];
  649. shadowState = value;
  650. }
  651. }
  652. - (ALVector) velocity
  653. {
  654. ALVector result;
  655. OPTIONALLY_SYNCHRONIZED(self)
  656. {
  657. [ALWrapper getSource3f:sourceId parameter:AL_VELOCITY v1:&result.x v2:&result.y v3:&result.z];
  658. }
  659. return result;
  660. }
  661. - (void) setVelocity:(ALVector) value
  662. {
  663. OPTIONALLY_SYNCHRONIZED(self)
  664. {
  665. if(self.suspended)
  666. {
  667. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  668. return;
  669. }
  670. [ALWrapper source3f:sourceId parameter:AL_VELOCITY v1:value.x v2:value.y v3:value.z];
  671. }
  672. }
  673. #pragma mark Suspend Handler
  674. - (void) addSuspendListener:(id<OALSuspendListener>) listenerIn
  675. {
  676. [suspendHandler addSuspendListener:listenerIn];
  677. }
  678. - (void) removeSuspendListener:(id<OALSuspendListener>) listenerIn
  679. {
  680. [suspendHandler removeSuspendListener:listenerIn];
  681. }
  682. - (bool) manuallySuspended
  683. {
  684. return suspendHandler.manuallySuspended;
  685. }
  686. - (void) setManuallySuspended:(bool) value
  687. {
  688. suspendHandler.manuallySuspended = value;
  689. }
  690. - (bool) interrupted
  691. {
  692. return suspendHandler.interrupted;
  693. }
  694. - (void) setInterrupted:(bool) value
  695. {
  696. suspendHandler.interrupted = value;
  697. }
  698. - (bool) suspended
  699. {
  700. return suspendHandler.suspended;
  701. }
  702. - (void) setSuspended:(bool) value
  703. {
  704. if(value)
  705. {
  706. shadowState = self.state;
  707. if(AL_PLAYING == shadowState)
  708. {
  709. [ALWrapper sourcePause:sourceId];
  710. }
  711. }
  712. else
  713. {
  714. // The shadow state holds the state we had when suspending.
  715. if(AL_PLAYING == shadowState)
  716. {
  717. // Because Apple's OpenAL implementation can't stack commands (it defers processing
  718. // to a later sequence point), we have to delay resuming playback.
  719. abortPlaybackResume = NO;
  720. [self performSelector:@selector(delayedResumePlayback) withObject:nil afterDelay:0.03];
  721. }
  722. }
  723. }
  724. - (void) delayedResumePlayback
  725. {
  726. if(!abortPlaybackResume)
  727. {
  728. [ALWrapper sourcePlay:sourceId];
  729. }
  730. }
  731. #pragma mark Playback
  732. - (void) preload:(ALBuffer*) bufferIn
  733. {
  734. OPTIONALLY_SYNCHRONIZED(self)
  735. {
  736. if(self.suspended)
  737. {
  738. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  739. return;
  740. }
  741. [self stopActions];
  742. if(self.playing || self.paused)
  743. {
  744. [self stop];
  745. }
  746. self.buffer = bufferIn;
  747. }
  748. }
  749. - (id<ALSoundSource>) play
  750. {
  751. OPTIONALLY_SYNCHRONIZED(self)
  752. {
  753. if(self.suspended)
  754. {
  755. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  756. return nil;
  757. }
  758. [self stopActions];
  759. if(self.playing)
  760. {
  761. if(!interruptible)
  762. {
  763. return nil;
  764. }
  765. [self stop];
  766. }
  767. if(self.paused)
  768. {
  769. [self stop];
  770. }
  771. if([ALWrapper sourcePlay:sourceId])
  772. {
  773. shadowState = AL_PLAYING;
  774. }
  775. else
  776. {
  777. shadowState = AL_STOPPED;
  778. }
  779. }
  780. return self;
  781. }
  782. - (id<ALSoundSource>) play:(ALBuffer*) bufferIn
  783. {
  784. return [self play:bufferIn loop:NO];
  785. }
  786. - (id<ALSoundSource>) play:(ALBuffer*) bufferIn loop:(bool) loop
  787. {
  788. OPTIONALLY_SYNCHRONIZED(self)
  789. {
  790. if(self.suspended)
  791. {
  792. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  793. return nil;
  794. }
  795. [self stopActions];
  796. if(self.playing)
  797. {
  798. if(!interruptible)
  799. {
  800. return nil;
  801. }
  802. [self stop];
  803. }
  804. self.buffer = bufferIn;
  805. self.looping = loop;
  806. if([ALWrapper sourcePlay:sourceId])
  807. {
  808. shadowState = AL_PLAYING;
  809. }
  810. else
  811. {
  812. shadowState = AL_STOPPED;
  813. }
  814. }
  815. return self;
  816. }
  817. - (id<ALSoundSource>) play:(ALBuffer*) bufferIn gain:(float) gainIn pitch:(float) pitchIn pan:(float) panIn loop:(bool) loopIn
  818. {
  819. OPTIONALLY_SYNCHRONIZED(self)
  820. {
  821. if(self.suspended)
  822. {
  823. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  824. return nil;
  825. }
  826. [self stopActions];
  827. if(self.playing)
  828. {
  829. if(!interruptible)
  830. {
  831. return nil;
  832. }
  833. [self stop];
  834. }
  835. self.buffer = bufferIn;
  836. // Set gain, pitch, and pan
  837. self.gain = gainIn;
  838. self.pitch = pitchIn;
  839. self.pan = panIn;
  840. self.looping = loopIn;
  841. if([ALWrapper sourcePlay:sourceId])
  842. {
  843. shadowState = AL_PLAYING;
  844. }
  845. else
  846. {
  847. shadowState = AL_STOPPED;
  848. }
  849. }
  850. return self;
  851. }
  852. - (void) stop
  853. {
  854. OPTIONALLY_SYNCHRONIZED(self)
  855. {
  856. if(self.suspended)
  857. {
  858. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  859. return;
  860. }
  861. abortPlaybackResume = YES;
  862. [self stopActions];
  863. [ALWrapper sourceStop:sourceId];
  864. shadowState = AL_STOPPED;
  865. }
  866. }
  867. - (void) rewind
  868. {
  869. OPTIONALLY_SYNCHRONIZED(self)
  870. {
  871. if(self.suspended)
  872. {
  873. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  874. return;
  875. }
  876. abortPlaybackResume = YES;
  877. [self stopActions];
  878. [ALWrapper sourceRewind:sourceId];
  879. shadowState = AL_INITIAL;
  880. }
  881. }
  882. - (void) fadeTo:(float) value
  883. duration:(float) duration
  884. target:(id) target
  885. selector:(SEL) selector
  886. {
  887. // Must always be synchronized
  888. @synchronized(self)
  889. {
  890. if(self.suspended)
  891. {
  892. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  893. return;
  894. }
  895. [self stopFade];
  896. gainAction = [[OALSequentialActions actions:
  897. [OALGainAction actionWithDuration:duration endValue:value],
  898. [OALCallAction actionWithCallTarget:target selector:selector withObject:self],
  899. nil] retain];
  900. [gainAction runWithTarget:self];
  901. }
  902. }
  903. - (void) stopFade
  904. {
  905. // Must always be synchronized
  906. @synchronized(self)
  907. {
  908. if(self.suspended)
  909. {
  910. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  911. return;
  912. }
  913. [gainAction stopAction];
  914. [gainAction release];
  915. gainAction = nil;
  916. }
  917. }
  918. - (void) panTo:(float) value
  919. duration:(float) duration
  920. target:(id) target
  921. selector:(SEL) selector
  922. {
  923. // Must always be synchronized
  924. @synchronized(self)
  925. {
  926. if(self.suspended)
  927. {
  928. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  929. return;
  930. }
  931. [self stopPan];
  932. gainAction = [[OALSequentialActions actions:
  933. [OALPanAction actionWithDuration:duration endValue:value],
  934. [OALCallAction actionWithCallTarget:target selector:selector withObject:self],
  935. nil] retain];
  936. [gainAction runWithTarget:self];
  937. }
  938. }
  939. - (void) stopPan
  940. {
  941. // Must always be synchronized
  942. @synchronized(self)
  943. {
  944. if(self.suspended)
  945. {
  946. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  947. return;
  948. }
  949. [gainAction stopAction];
  950. [gainAction release];
  951. gainAction = nil;
  952. }
  953. }
  954. - (void) pitchTo:(float) value
  955. duration:(float) duration
  956. target:(id) target
  957. selector:(SEL) selector
  958. {
  959. // Must always be synchronized
  960. @synchronized(self)
  961. {
  962. if(self.suspended)
  963. {
  964. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  965. return;
  966. }
  967. [self stopPitch];
  968. gainAction = [[OALSequentialActions actions:
  969. [OALPitchAction actionWithDuration:duration endValue:value],
  970. [OALCallAction actionWithCallTarget:target selector:selector withObject:self],
  971. nil] retain];
  972. [gainAction runWithTarget:self];
  973. }
  974. }
  975. - (void) stopPitch
  976. {
  977. // Must always be synchronized
  978. @synchronized(self)
  979. {
  980. if(self.suspended)
  981. {
  982. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  983. return;
  984. }
  985. [gainAction stopAction];
  986. [gainAction release];
  987. gainAction = nil;
  988. }
  989. }
  990. - (void) stopActions
  991. {
  992. [self stopFade];
  993. [self stopPan];
  994. [self stopPitch];
  995. }
  996. - (void) clear
  997. {
  998. OPTIONALLY_SYNCHRONIZED(self)
  999. {
  1000. self.manuallySuspended = NO;
  1001. [self stop];
  1002. self.buffer = nil;
  1003. }
  1004. }
  1005. #pragma mark Queued Playback
  1006. - (bool) queueBuffer:(ALBuffer*) bufferIn
  1007. {
  1008. return [self queueBuffer:bufferIn repeats:0];
  1009. }
  1010. - (bool) queueBuffer:(ALBuffer*) bufferIn repeats:(NSUInteger) repeats
  1011. {
  1012. OPTIONALLY_SYNCHRONIZED(self)
  1013. {
  1014. if(self.suspended)
  1015. {
  1016. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  1017. return NO;
  1018. }
  1019. if(AL_STATIC == self.state)
  1020. {
  1021. self.buffer = nil;
  1022. }
  1023. NSUInteger totalTimes = repeats + 1;
  1024. ALuint* bufferIds = (ALuint*)malloc(sizeof(ALuint) * totalTimes);
  1025. ALuint bufferId = bufferIn.bufferId;
  1026. for(NSUInteger i = 0; i < totalTimes; i++)
  1027. {
  1028. bufferIds[i] = bufferId;
  1029. }
  1030. bool result = [ALWrapper sourceQueueBuffers:sourceId numBuffers:totalTimes bufferIds:bufferIds];
  1031. free(bufferIds);
  1032. return result;
  1033. }
  1034. }
  1035. - (bool) queueBuffers:(NSArray*) buffers
  1036. {
  1037. return [self queueBuffers:buffers repeats:0];
  1038. }
  1039. - (bool) queueBuffers:(NSArray*) buffers repeats:(NSUInteger) repeats
  1040. {
  1041. OPTIONALLY_SYNCHRONIZED(self)
  1042. {
  1043. if(self.suspended)
  1044. {
  1045. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  1046. return NO;
  1047. }
  1048. if(AL_STATIC == self.state)
  1049. {
  1050. self.buffer = nil;
  1051. }
  1052. NSUInteger numBuffers = [buffers count];
  1053. NSUInteger totalTimes = repeats + 1;
  1054. ALuint* bufferIds = (ALuint*)malloc(sizeof(ALuint) * totalTimes * numBuffers);
  1055. NSUInteger bufferNum;
  1056. for(NSUInteger i = 0; i < totalTimes; i++)
  1057. {
  1058. bufferNum = 0;
  1059. for(ALBuffer* buf in buffers)
  1060. {
  1061. bufferIds[(i * numBuffers) + bufferNum] = buf.bufferId;
  1062. bufferNum++;
  1063. }
  1064. }
  1065. bool result = [ALWrapper sourceQueueBuffers:sourceId numBuffers:totalTimes*numBuffers bufferIds:bufferIds];
  1066. free(bufferIds);
  1067. return result;
  1068. }
  1069. }
  1070. - (bool) unqueueBuffer:(ALBuffer*) bufferIn
  1071. {
  1072. OPTIONALLY_SYNCHRONIZED(self)
  1073. {
  1074. if(self.suspended)
  1075. {
  1076. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  1077. return NO;
  1078. }
  1079. ALuint bufferId = bufferIn.bufferId;
  1080. return [ALWrapper sourceUnqueueBuffers:sourceId numBuffers:1 bufferIds:&bufferId];
  1081. }
  1082. }
  1083. - (bool) unqueueBuffers:(NSArray*) buffers
  1084. {
  1085. OPTIONALLY_SYNCHRONIZED(self)
  1086. {
  1087. if(self.suspended)
  1088. {
  1089. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  1090. return NO;
  1091. }
  1092. if(AL_STATIC == self.state)
  1093. {
  1094. self.buffer = nil;
  1095. }
  1096. int numBuffers = [buffers count];
  1097. ALuint* bufferIds = malloc(sizeof(ALuint) * numBuffers);
  1098. int i = 0;
  1099. for(ALBuffer* buf in buffers)
  1100. {
  1101. bufferIds[i] = buf.bufferId;
  1102. }
  1103. bool result = [ALWrapper sourceUnqueueBuffers:sourceId numBuffers:numBuffers bufferIds:bufferIds];
  1104. free(bufferIds);
  1105. return result;
  1106. }
  1107. }
  1108. #pragma mark Internal Use
  1109. - (bool) requestUnreserve:(bool) interrupt
  1110. {
  1111. OPTIONALLY_SYNCHRONIZED(self)
  1112. {
  1113. if(self.playing)
  1114. {
  1115. if(!self.interruptible || !interrupt)
  1116. {
  1117. return NO;
  1118. }
  1119. [self stop];
  1120. }
  1121. self.buffer = nil;
  1122. }
  1123. return YES;
  1124. }
  1125. @end