]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/cocoa/sound.mm
adding raw_control for osx
[wxWidgets.git] / src / cocoa / sound.mm
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/cocoa/sound.mm
3// Purpose: wxSound class implementation: optional
4// Authors: David Elliott, Ryan Norton
5// Modified by:
6// Created: 2004-10-02
7// RCS-ID: $Id$
8// Copyright: (c) 2004 David Elliott, Ryan Norton
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13#if wxUSE_SOUND
14
15#ifndef WX_PRECOMP
16 #include "wx/app.h"
17 #include "wx/log.h"
18#endif //ndef WX_PRECOMP
19#include "wx/sound.h"
20#include "wx/evtloop.h"
21
22#include "wx/cocoa/autorelease.h"
23#include "wx/cocoa/string.h"
24#include "wx/cocoa/log.h"
25
26#include "wx/cocoa/objc/objc_uniquifying.h"
27
28#import <AppKit/NSSound.h>
29#import <Foundation/NSData.h>
30
31static WX_NSSound s_currentSound = nil;
32static bool s_loopCurrentSound = false;
33
34// ========================================================================
35// wxNSSoundDelegate
36// ========================================================================
37@interface wxNSSoundDelegate : NSObject
38{
39}
40
41// Delegate methods
42- (void)sound:(NSSound *)theSound didFinishPlaying:(BOOL)finishedPlaying;
43@end // interface wxNSSoundDelegate : NSObject
44WX_DECLARE_GET_OBJC_CLASS(wxNSSoundDelegate,NSObject)
45
46@implementation wxNSSoundDelegate : NSObject
47
48- (void)sound:(NSSound *)theSound didFinishPlaying:(BOOL)finishedPlaying
49{
50 // If s_currentSound is not us then some other sound has played.
51 // We can safely ignore this as s_currentSound will have been released
52 // before being set to a different value.
53 if(s_currentSound!=theSound)
54 return;
55 // If playing finished successfully and we are looping, play again.
56 if (finishedPlaying && s_loopCurrentSound)
57 [s_currentSound play];
58 // Otherwise we are done, there is no more current sound playing.
59 else
60 {
61 if(s_currentSound) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("[wxNSSoundDelegate -sound:didFinishPlaying:] [s_currentSound=%p retainCount]=%d (about to release)"),s_currentSound,[s_currentSound retainCount]);
62 [s_currentSound release];
63 s_currentSound = nil;
64 // Make sure we get out of any modal event loops immediately.
65 // NOTE: When the sound finishes playing Cocoa normally does have
66 // an event so this is probably not necessary.
67 wxTheApp->WakeUpIdle();
68 }
69}
70
71@end // wxNSSoundDelegate
72WX_IMPLEMENT_GET_OBJC_CLASS(wxNSSoundDelegate,NSObject)
73
74const wxObjcAutoRefFromAlloc<struct objc_object*> wxSound::sm_cocoaDelegate = [[WX_GET_OBJC_CLASS(wxNSSoundDelegate) alloc] init];
75
76// ------------------------------------------------------------------
77// wxSound
78// ------------------------------------------------------------------
79
80wxSound::wxSound(const wxSound& sound)
81: m_cocoaNSSound(sound.m_cocoaNSSound)
82{
83 [m_cocoaNSSound retain];
84}
85
86wxSound::~wxSound()
87{
88 SetNSSound(nil);
89}
90
91bool wxSound::Create(const wxString& fileName, bool isResource)
92{
93 wxAutoNSAutoreleasePool thePool;
94
95 if (isResource)
96 SetNSSound([NSSound soundNamed:wxNSStringWithWxString(fileName)]);
97 else
98 {
99 SetNSSound([[NSSound alloc] initWithContentsOfFile:wxNSStringWithWxString(fileName) byReference:YES]);
100 [m_cocoaNSSound release];
101 }
102
103 return m_cocoaNSSound;
104}
105
106bool wxSound::LoadWAV(const wxUint8 *data, size_t length, bool copyData)
107{
108 NSData* theData;
109 if(copyData)
110 theData = [[NSData alloc] initWithBytes:const_cast<wxUint8*>(data) length:length];
111 else
112 theData = [[NSData alloc] initWithBytesNoCopy:const_cast<wxUint8*>(data) length:length];
113 SetNSSound([[NSSound alloc] initWithData:theData]);
114 [m_cocoaNSSound release];
115 [theData release];
116 return m_cocoaNSSound;
117}
118
119void wxSound::SetNSSound(WX_NSSound cocoaNSSound)
120{
121 bool need_debug = cocoaNSSound || m_cocoaNSSound;
122 if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxSound=%p::SetNSSound [m_cocoaNSSound=%p retainCount]=%d (about to release)"),this,m_cocoaNSSound,[m_cocoaNSSound retainCount]);
123 [cocoaNSSound retain];
124 [m_cocoaNSSound release];
125 m_cocoaNSSound = cocoaNSSound;
126 [m_cocoaNSSound setDelegate:sm_cocoaDelegate];
127 if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxSound=%p::SetNSSound [cocoaNSSound=%p retainCount]=%d (just retained)"),this,cocoaNSSound,[cocoaNSSound retainCount]);
128}
129
130bool wxSound::DoPlay(unsigned flags) const
131{
132 Stop(); // this releases and nils s_currentSound
133
134 // NOTE: We set s_currentSound to the current sound in all cases so that
135 // functions like Stop and IsPlaying can work. It is NOT necessary for
136 // the NSSound to be retained by us for it to continue playing. Cocoa
137 // retains the NSSound when it is played and relases it when finished.
138
139 wxASSERT(!s_currentSound);
140 s_currentSound = [m_cocoaNSSound retain];
141 wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxSound=%p::DoPlay [s_currentSound=%p retainCount]=%d (just retained)"),this,s_currentSound,[s_currentSound retainCount]);
142 s_loopCurrentSound = (flags & wxSOUND_LOOP) == wxSOUND_LOOP;
143
144 if (flags & wxSOUND_ASYNC)
145 return [m_cocoaNSSound play];
146 else
147 {
148 wxASSERT_MSG(!s_loopCurrentSound,wxT("It is silly to block waiting for a looping sound to finish. Disabling looping"));
149 // actually, it'd probably work although it's kind of stupid to
150 // block here waiting for a sound that's never going to end.
151 // Granted Stop() could be called somehow, but again, silly.
152 s_loopCurrentSound = false;
153
154 if(![m_cocoaNSSound play])
155 return false;
156
157 // Process events until the delegate sets s_currentSound to nil
158 // and/or a different sound plays.
159 while (s_currentSound==m_cocoaNSSound)
160 wxEventLoop::GetActive()->Dispatch();
161 return true;
162 }
163}
164
165bool wxSound::IsPlaying()
166{
167 // Normally you can send a message to a nil object and it will return
168 // nil. That behaviour would probably be okay here but in general it's
169 // not recommended to send a message to a nil object if the return
170 // value is not an object. Better safe than sorry.
171 if(s_currentSound)
172 return [s_currentSound isPlaying];
173 else
174 return false;
175}
176
177void wxSound::Stop()
178{
179 // Clear the looping flag so that if the sound finishes playing before
180 // stop is called the sound will already be released and niled.
181 s_loopCurrentSound = false;
182 [s_currentSound stop];
183 /* It's possible that sound:didFinishPlaying: was called and released
184 s_currentSound but it doesn't matter since it will have set it to nil */
185 if(s_currentSound) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxSound::Stop [s_currentSound=%p retainCount]=%d (about to release)"),s_currentSound,[s_currentSound retainCount]);
186 [s_currentSound release];
187 s_currentSound = nil;
188}
189
190#endif //wxUSE_SOUND