wxSound for 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 = NO;
36 bool isLastSoundInScope = NO;
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 = NO)
56     {
57         [lastSound release];
58         [self release];
59     }
60 }
61
62 @end // wxNSSoundDelegate
63
64 // ------------------------------------------------------------------
65 //          wxSound
66 // ------------------------------------------------------------------
67
68 wxSound::wxSound()
69 : m_hSnd(NULL), m_waveLength(0)
70 {
71 }
72
73 wxSound::wxSound(const wxString& sFileName, bool isResource)
74 : m_hSnd(NULL), m_waveLength(0)
75 {
76     Create(sFileName, isResource);
77 }
78
79 wxSound::wxSound(int size, const wxByte* data)
80 : m_hSnd(NULL), m_waveLength(size)
81 {
82     NSData* theData = [[NSData alloc] dataWithBytesNoCopy:(void*)data length:size];
83     m_hSnd = [[NSSound alloc] initWithData:theData];
84
85     m_cocoaSoundDelegate = [[wxNSSoundDelegate alloc] init];
86 }
87
88 wxSound::~wxSound()
89 {
90     if (m_hSnd != lastSound)
91     {
92         [m_hSnd release];
93         [m_cocoaSoundDelegate release];
94     }
95     else
96         isLastSoundInScope = NO;
97 }
98
99 bool wxSound::Create(const wxString& fileName, bool isResource)
100 {
101     wxAutoNSAutoreleasePool thePool;
102
103     Stop();
104
105     if (isResource)
106     {
107             //oftype could be @"snd" @"wav" or @"aiff", nil or @"" autodetects (?)
108         m_hSnd = [[NSSound alloc] initWithContentsOfFile:
109             [[NSBundle mainBundle] pathForResource:wxNSStringWithWxString(fileName) ofType:nil] 
110             byReference:NO];    
111     }
112     else
113             m_hSnd = [[NSSound alloc] initWithContentsOfFile:wxNSStringWithWxString(fileName) byReference:YES];
114
115     m_cocoaSoundDelegate = [[wxNSSoundDelegate alloc] init];
116
117     m_sndname = fileName;
118     return m_hSnd != nil;
119 }
120
121 bool wxSound::DoPlay(unsigned flags) const
122 {
123     wxASSERT_MSG(!( (flags & wxSOUND_SYNC) && (flags & wxSOUND_LOOP)), 
124                 wxT("Invalid flag combination passed to wxSound::Play"));
125
126     Stop();
127
128     if (flags & wxSOUND_ASYNC)
129     {
130         lastSound = m_hSnd;
131         isLastSoundLooping = (flags & wxSOUND_LOOP) == wxSOUND_LOOP;
132         isLastSoundInScope = YES;
133        [m_hSnd setDelegate:m_cocoaSoundDelegate];
134         return [m_hSnd play];
135     }
136     else
137     {
138         [m_hSnd setDelegate:nil];
139    
140            //play until done
141         bool bOK = [m_hSnd play];
142         
143         while ([m_hSnd isPlaying]) 
144         {
145             wxTheApp->Yield(false);
146         }
147         return bOK;
148     }
149 }
150
151 bool wxSound::IsPlaying()
152 {
153     return [lastSound isPlaying];
154 }
155
156 void wxSound::Stop()
157 {
158     if (isLastSoundInScope)
159     {
160         isLastSoundInScope = NO;
161         
162         //remember that even though we're
163         //programatically stopping it, the
164         //delegate will still be called - 
165         //so it will free the memory here
166         [((NSSound*&)lastSound) stop];
167     }
168     
169     lastSound = nil;
170 }
171
172 #endif //wxUSE_SOUND