Renamed m_hSnd to m_cocoaNSSound (match rest of wxCocoa).
[wxWidgets.git] / src / cocoa / sound.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        sound.cpp
3 // Purpose:     wxSound class implementation: optional
4 // Author:      Ryan Norton
5 // Modified by: 
6 // Created:     2004-10-02
7 // RCS-ID:      $Id$
8 // Copyright:   (c) Ryan Norton
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "sound.h"
14 #endif
15
16 #include "wx/object.h"
17 #include "wx/string.h"
18 #include "wx/sound.h"
19
20 #if wxUSE_SOUND
21
22 #include "wx/app.h"
23 #include "wx/cocoa/autorelease.h"
24 #include "wx/cocoa/string.h"
25
26 #import <AppKit/AppKit.h>
27
28 //
29 // NB:  Vaclav's new wxSound API is really tricky -
30 // Basically, we need to make sure that if the wxSound
31 // object is still in scope we don't release it's NSSound
32 //
33
34 WX_NSSound lastSound=NULL;
35 bool isLastSoundLooping = false;
36 bool isLastSoundInScope = false;
37
38 // ========================================================================
39 // wxNSSoundDelegate
40 // ========================================================================
41 @interface wxNSSoundDelegate : NSObject
42 {
43 }
44
45 // Delegate methods
46 - (void)sound:(NSSound *)theSound didFinishPlaying:(BOOL)bOK;
47 @end // interface wxNSSoundDelegate : NSObject
48
49 @implementation wxNSSoundDelegate : NSObject
50
51 - (void)sound:(NSSound *)theSound didFinishPlaying:(BOOL)bOK
52 {
53     if (bOK && isLastSoundLooping)
54         [lastSound play];
55     else if (!isLastSoundInScope)
56     {
57         [lastSound release];
58         [self release];
59     }
60 }
61
62 @end // wxNSSoundDelegate
63
64 const wxObjcAutoRefFromAlloc<struct objc_object*> wxSound::sm_cocoaDelegate = [[wxNSSoundDelegate alloc] init];
65
66 // ------------------------------------------------------------------
67 //          wxSound
68 // ------------------------------------------------------------------
69
70 wxSound::wxSound()
71 :   m_cocoaNSSound(nil)
72 ,   m_waveLength(0)
73 {
74 }
75
76 wxSound::wxSound(const wxString& sFileName, bool isResource)
77 :   m_cocoaNSSound(nil)
78 ,   m_waveLength(0)
79 {
80     Create(sFileName, isResource);
81 }
82
83 wxSound::wxSound(int size, const wxByte* data)
84 :   m_cocoaNSSound(nil)
85 ,   m_waveLength(size)
86 {
87     NSData* theData = [[NSData alloc] dataWithBytesNoCopy:(void*)data length:size];
88     m_cocoaNSSound = [[NSSound alloc] initWithData:theData];
89
90 }
91
92 wxSound::~wxSound()
93 {
94     if (m_cocoaNSSound != lastSound)
95     {
96         [m_cocoaNSSound release];
97     }
98     else
99         isLastSoundInScope = false;
100 }
101
102 bool wxSound::Create(const wxString& fileName, bool isResource)
103 {
104     wxAutoNSAutoreleasePool thePool;
105
106     Stop();
107
108     if (isResource)
109     {
110         //oftype could be @"snd" @"wav" or @"aiff"; nil or @"" autodetects (?)
111         m_cocoaNSSound = [[NSSound alloc]
112             initWithContentsOfFile:[[NSBundle mainBundle]
113                     pathForResource:wxNSStringWithWxString(fileName)
114                     ofType:nil]
115             byReference:YES];
116     }
117     else
118             m_cocoaNSSound = [[NSSound alloc] initWithContentsOfFile:wxNSStringWithWxString(fileName) byReference:YES];
119
120     m_sndname = fileName;
121     return m_cocoaNSSound;
122 }
123
124 bool wxSound::DoPlay(unsigned flags) const
125 {
126     wxASSERT_MSG(!( (flags & wxSOUND_SYNC) && (flags & wxSOUND_LOOP)),
127                 wxT("Invalid flag combination passed to wxSound::Play"));
128
129     Stop();
130
131     if (flags & wxSOUND_ASYNC)
132     {
133         lastSound = m_cocoaNSSound;
134         isLastSoundLooping = (flags & wxSOUND_LOOP) == wxSOUND_LOOP;
135         isLastSoundInScope = true;
136         [m_cocoaNSSound setDelegate:sm_cocoaDelegate];
137         return [m_cocoaNSSound play];
138     }
139     else
140     {
141         [m_cocoaNSSound setDelegate:nil];
142
143         //play until done
144         bool bOK = [m_cocoaNSSound play];
145
146         while ([m_cocoaNSSound isPlaying])
147         {
148             wxTheApp->Yield(false);
149         }
150         return bOK;
151     }
152 }
153
154 bool wxSound::IsPlaying()
155 {
156     return [lastSound isPlaying];
157 }
158
159 void wxSound::Stop()
160 {
161     if (isLastSoundInScope)
162     {
163         isLastSoundInScope = false;
164
165         //remember that even though we're
166         //programatically stopping it, the
167         //delegate will still be called -
168         //so it will free the memory here
169         [((NSSound*&)lastSound) stop];
170     }
171
172     lastSound = nil;
173 }
174
175 #endif //wxUSE_SOUND