1 // This embarassing hack exists purely because EMACS' electric-c indentation
2 // mode is too clever by half...
4 #define BEGIN_EXTERN_C extern "C" {
5 #define END_EXTERN_C };
11 #include <CoreServices/CoreServices.h>
15 // In order to get along with the threading restrictions of Carbon
17 // "Carbon is not thread-safe for preemptive threads. You really need
18 // to use Carbon only from your main thread, and not from other
21 // this file implements a special main() function for the Mac OS, as well as
22 // implementing a command queue so that other threads may make Carbon toolbox
23 // calls safely (i.e. by asking the Mac main thread to do so).
25 // The job of the main thread is to handle events. The main thread also
26 // drives the sequence grabber (by calling SGIdle when appropriate) and the
28 // The need to fiddle with these features is communicated via custom Carbon
29 // Events; the Carbon Event Manager is MPThread-safe (but not pthread
30 // safe), so I have made sure that PWLIB uses MPThreads so they can talk
31 // directly to the main thread.
33 // Oh yeah, and it calls the PProcess::Main() function, too. Wouldn't want
34 // to forget about that. That gets called on yet another MPThread, whose
35 // termination drives the shutdown of the main thread. I hope.
37 // Some of the ideas here come from the OTMP library. Some of them don't.
38 // Guess which set turns out to be more reliable...
41 // A thread wishing to have a Carbon action performed creates one of these
42 // structures on its stack and calls CarbonQueue; when CarbonQueue returns,
43 // the action has been performed.
45 // CarbonQueue initializes a semaphore in the carbonRequest object, places
46 // the object on an OTLIFO queue, and wakes up the main thread with
47 // a custom Carbon Event. Then it sleeps on the semaphore.
49 // The main thread's handler checks the queue for Carbon commands needing
50 // to be made in the context of the process main thread. When it has
51 // performed each call, it signals the semaphore and goes to the next
52 // request. A few commands cannot be completed synchronously by the main
53 // thread; they pass responsibility for the semaphore to a callback function.
57 // audio recorder commands
58 kOpenRecorder
= 'opre',
59 // arguments: const char *name, struct soundParams *
60 // returns: reference to new audio recorder OR error
61 kSetFormatRecorder
= 'sfre',
62 // arguments: int reference, int soundParams *
64 kCloseRecorder
= 'clre',
65 // arguments: int reference
67 kStartRecorder
= 'stre',
68 // arguments: int reference, struct ringbuffer *
70 kStopRecorder
= 'spre',
71 // arguments: int reference
73 // audio player commands
75 // arguments: name, soundParams *
76 // returns: reference to new audio player OR error
77 kSetFormatPlayer
= 'sfpl',
78 // arguments: int reference, soundParams *
80 kClosePlayer
= 'cppl',
81 // arguments: int reference
84 // arguments: int reference, char *buffer, int buflen
86 // note: returns when sound is enqueued, not finished.
87 kStopPlayer
= 'stpl', // ssshhh!!!
88 // arguments: int reference
91 // arguments: int reference
92 // returns: 0/1 if playing
93 kWaitForPlayCompletion
= 'wapl',
94 // arguments: int reference
103 unsigned short sp_channels
;
104 unsigned short sp_samplesize
;
105 unsigned long sp_samplerate
;
107 soundParams(int c
, int s
, long r
)
108 : sp_channels(c
), sp_samplesize(s
), sp_samplerate(r
)
113 typedef struct commandRequest commandRequest
;
114 OSStatus
CarbonQueue(commandRequest
*request
);
116 struct commandRequest
118 OTLink m_next
; // it's a pointer
120 carbonCommand_t m_command
;
121 unsigned long m_arg1
, m_arg2
, m_arg3
, m_arg4
;
122 unsigned long m_result
; // if useful data is returned
123 OSStatus m_status
; // error return
124 MPSemaphoreID m_done
;
126 commandRequest(carbonCommand_t cmd
,
127 unsigned long a1
= 0,
128 unsigned long a2
= 0,
129 unsigned long a3
= 0,
130 unsigned long a4
= 0)
131 : m_command(cmd
), m_arg1(a1
), m_arg2(a2
), m_arg3(a3
), m_arg4(a4
),
132 m_result(0), m_status(0), m_done(0)
135 : m_command(kNotACommand
), m_arg1(0), m_arg2(0), m_arg3(0), m_arg4(0),
136 m_result(0), m_status(0), m_done(0)
138 // convenience constructors
139 commandRequest(carbonCommand_t cmd
,
140 const unsigned char *a1
,
141 const soundParams
*a2
)
143 m_arg1((unsigned long)a1
), m_arg2((unsigned long)a2
),
144 m_arg3(0), m_arg4(0),
145 m_result(0), m_status(0), m_done(0)
147 commandRequest(carbonCommand_t cmd
,
149 const soundParams
*a2
)
151 m_arg1(a1
), m_arg2((unsigned long)a2
), m_arg3(0), m_arg4(0),
152 m_result(0), m_status(0), m_done(0)
154 commandRequest(carbonCommand_t cmd
,
158 m_arg1(a1
), m_arg2((unsigned long)a2
), m_arg3(0), m_arg4(0),
159 m_result(0), m_status(0), m_done(0)
161 commandRequest(carbonCommand_t cmd
,
166 m_arg1(a1
), m_arg2((unsigned long)a2
), m_arg3(a3
), m_arg4(0),
167 m_result(0), m_status(0), m_done(0)
169 // and a convenience inline
170 OSStatus
CarbonQueue()
172 return ::CarbonQueue(this);