root/branches/libfreebob-2.0/src/libstreaming/Port.cpp

Revision 227, 9.3 kB (checked in by pieterpalmers, 18 years ago)

- another day of good progress comes to and end...
- compiles and runs, only the midi stuff and the xrun handling remain.

I'll also have to rework the C API somewhat.

Line 
1 /* $Id$ */
2
3 /*
4  *   FreeBob Streaming API
5  *   FreeBob = Firewire (pro-)audio for linux
6  *
7  *   http://freebob.sf.net
8  *
9  *   Copyright (C) 2005,2006 Pieter Palmers <pieterpalmers@users.sourceforge.net>
10  *
11  *   This program is free software {} you can redistribute it and/or modify
12  *   it under the terms of the GNU General Public License as published by
13  *   the Free Software Foundation {} either version 2 of the License, or
14  *   (at your option) any later version.
15  *
16  *   This program is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY {} without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with this program {} if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  *
26  *
27  */
28
29 #include "Port.h"
30  #include <stdlib.h>
31 #include <assert.h>
32
33
34 namespace FreebobStreaming {
35
36 IMPL_DEBUG_MODULE( Port, Port, DEBUG_LEVEL_NORMAL );
37
38 Port::Port(std::string name, enum E_PortType porttype, enum E_Direction direction)
39         : m_Name(name),
40         m_SignalType(E_PeriodSignalled),
41         m_BufferType(E_PointerBuffer),
42         m_enabled(true),
43         m_buffersize(0),
44         m_eventsize(0),
45         m_DataType(E_Int24),
46         m_PortType(porttype),
47         m_Direction(direction),
48         m_buffer(0),
49         m_ringbuffer(0),
50         m_use_external_buffer(false)
51 {
52
53 }
54
55 /**
56  * The idea is that you set all port parameters, and then initialize the port.
57  * This allocates all resources and makes the port usable. However, you can't
58  * change the port properties anymore after this.
59  *
60  * @return true if successfull. false if not (all resources are freed).
61  */
62 bool Port::init() {
63         if (m_initialized) {
64                 debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
65                 return false;
66         }       
67        
68         if (m_buffersize==0) {
69                 debugFatal("Cannot initialize a port with buffersize=0\n");
70                 return false;   
71         }
72        
73         switch (m_BufferType) {
74                 case E_PointerBuffer:
75                         if (m_use_external_buffer) {
76                                 // don't do anything
77                         } else if (!allocateInternalBuffer()) {
78                                 debugFatal("Could not allocate internal buffer!\n");
79                                 return false;
80                         }
81                         break;
82                        
83                 case E_RingBuffer:
84                         if (m_use_external_buffer) {
85                                 debugFatal("Cannot use an external ringbuffer! \n");
86                                 return false;
87                         } else if (!allocateInternalRingBuffer()) {
88                                 debugFatal("Could not allocate internal ringbuffer!\n");
89                                 return false;
90                         }
91                         break;
92                 default:
93                         debugFatal("Unsupported buffer type! (%d)\n",(int)m_BufferType);
94                         return false;
95                         break;
96         }
97
98         m_initialized=true;
99        
100         m_eventsize=getEventSize(); // this won't change, so cache it
101        
102         return m_initialized;
103 }
104
105 void Port::setVerboseLevel(int l) {
106         setDebugLevel(l);
107 }
108
109 bool Port::setName(std::string name) {
110         debugOutput( DEBUG_LEVEL_VERBOSE, "Setting name to %s for port %s\n",name.c_str(),m_Name.c_str());
111        
112         if (m_initialized) {
113                 debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
114                 return false;
115         }
116        
117         m_Name=name;
118        
119         return true;
120 }
121
122 bool Port::setBufferSize(unsigned int newsize) {
123         debugOutput( DEBUG_LEVEL_VERBOSE, "Setting buffersize to %d for port %s\n",newsize,m_Name.c_str());
124         if (m_initialized) {
125                 debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
126                 return false;
127         }
128
129         m_buffersize=newsize;
130         return true;
131
132 }
133
134 unsigned int Port::getEventSize() {
135         switch (m_DataType) {
136                 case E_Float:
137                         return sizeof(float);
138                 case E_Int24: // 24 bit 2's complement, packed in a 32bit integer (LSB's)
139                         return sizeof(uint32_t);
140                 case E_MidiEvent:
141                         return sizeof(uint32_t);
142                 default:
143                         return 0;
144         }
145 }
146
147 bool Port::setDataType(enum E_DataType d) {
148         debugOutput( DEBUG_LEVEL_VERBOSE, "Setting datatype to %d for port %s\n",(int) d,m_Name.c_str());
149         if (m_initialized) {
150                 debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
151                 return false;
152         }
153        
154         // do some sanity checks
155         bool type_is_ok=false;
156         switch (m_PortType) {
157                 case E_Audio:
158                         if(d == E_Int24) type_is_ok=true;
159                         if(d == E_Float) type_is_ok=true;
160                         break;
161                 case E_Midi:
162                         if(d == E_MidiEvent) type_is_ok=true;
163                         break;
164                 case E_Control:
165                         if(d == E_Default) type_is_ok=true;
166                         break;
167                 default:
168                         break;
169         }
170        
171         if(!type_is_ok) {
172                 debugFatal("Datatype not supported by this type of port!\n");
173                 return false;
174         }
175        
176         m_DataType=d;
177         return true;
178 }
179
180 bool Port::setSignalType(enum E_SignalType s) {
181         debugOutput( DEBUG_LEVEL_VERBOSE, "Setting signaltype to %d for port %s\n",(int)s,m_Name.c_str());
182         if (m_initialized) {
183                 debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
184                 return false;
185         }
186        
187         // do some sanity checks
188         bool type_is_ok=false;
189         switch (m_PortType) {
190                 case E_Audio:
191                         if(s == E_PeriodSignalled) type_is_ok=true;
192                         break;
193                 case E_Midi:
194                         if(s == E_PacketSignalled) type_is_ok=true;
195                         break;
196                 case E_Control:
197                         if(s == E_PeriodSignalled) type_is_ok=true;
198                         break;
199                 default:
200                         break;
201         }
202        
203         if(!type_is_ok) {
204                 debugFatal("Signalling type not supported by this type of port!\n");
205                 return false;
206         }
207        
208         m_SignalType=s;
209         return true;
210
211 }
212
213 bool Port::setBufferType(enum E_BufferType b) {
214         debugOutput( DEBUG_LEVEL_VERBOSE, "Setting buffer type to %d for port %s\n",(int)b,m_Name.c_str());
215         if (m_initialized) {
216                 debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
217                 return false;
218         }
219        
220         // do some sanity checks
221         bool type_is_ok=false;
222         switch (m_PortType) {
223                 case E_Audio:
224                         if(b == E_PointerBuffer) type_is_ok=true;
225                         break;
226                 case E_Midi:
227                         if(b == E_RingBuffer) type_is_ok=true;
228                         break;
229                 case E_Control:
230                         break;
231                 default:
232                         break;
233         }
234        
235         if(!type_is_ok) {
236                 debugFatal("Buffer type not supported by this type of port!\n");
237                 return false;
238         }
239        
240         m_BufferType=b;
241         return true;
242
243 }
244
245 bool Port::useExternalBuffer(bool b) {
246        
247         debugOutput( DEBUG_LEVEL_VERBOSE, "Setting external buffer use to %d for port %s\n",(int)b,m_Name.c_str());
248        
249         if (m_initialized) {
250                 debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
251                 return false;
252         }
253
254         m_use_external_buffer=b;
255         return true;
256 }
257
258 // buffer handling api's for pointer buffers
259 /**
260  * Get the buffer address (being the external or the internal one).
261  *
262  * @param buff
263  */
264 void *Port::getBufferAddress() {
265         assert(m_BufferType==E_PointerBuffer);
266         return m_buffer;
267 };
268
269 /**
270  * Set the external buffer address.
271  * only call this when specifying an external buffer before init()
272  *
273  * @param buff
274  */
275 void Port::setExternalBufferAddress(void *buff) {
276         assert(m_BufferType==E_PointerBuffer);
277         assert(m_use_external_buffer); // don't call this with an internal buffer!
278         m_buffer=buff;
279 };
280
281 // buffer handling api's for ringbuffers
282 bool Port::writeEvent(void *event) {
283         assert(m_BufferType==E_RingBuffer);
284         assert(m_ringbuffer);
285        
286         char *byte=(char *)event;
287         debugOutput( DEBUG_LEVEL_VERBOSE, "Writing event %02X to port %s\n",(*byte)&0xFF,m_Name.c_str());
288        
289         return (freebob_ringbuffer_write(m_ringbuffer, byte, m_eventsize)==m_eventsize);
290 }
291
292 bool Port::readEvent(void *event) {
293         assert(m_ringbuffer);
294        
295         char *byte=(char *)event;
296         unsigned int read=freebob_ringbuffer_read(m_ringbuffer, byte, m_eventsize);
297        
298         debugOutput( DEBUG_LEVEL_VERBOSE, "Reading event %X from port %s\n",(*byte),m_Name.c_str());
299         return (read==m_eventsize);
300 }
301
302 int Port::writeEvents(void *event, unsigned int nevents) {
303         assert(m_BufferType==E_RingBuffer);
304         assert(m_ringbuffer);
305        
306         char *byte=(char *)event;
307         unsigned int bytes2write=m_eventsize*nevents;
308        
309         return (freebob_ringbuffer_write(m_ringbuffer, byte,bytes2write)/m_eventsize);
310
311 }
312
313 int Port::readEvents(void *event, unsigned int nevents) {
314         assert(m_ringbuffer);
315         char *byte=(char *)event;
316        
317         unsigned int bytes2read=m_eventsize*nevents;
318        
319         freebob_ringbuffer_read(m_ringbuffer, byte, bytes2read);
320         debugOutput( DEBUG_LEVEL_VERBOSE, "Reading events (%X) from port %s\n",(*byte),m_Name.c_str());
321        
322         return freebob_ringbuffer_read(m_ringbuffer, byte, bytes2read)/m_eventsize;
323 }
324
325
326 /* Private functions */
327
328 bool Port::allocateInternalBuffer() {
329         int event_size=getEventSize();
330        
331         debugOutput(DEBUG_LEVEL_VERBOSE,
332                     "Allocating internal buffer of %d events with size %d (%s)\n",
333                     m_buffersize, event_size, m_Name.c_str());
334
335         if(m_buffer) {
336                 debugWarning("already has an internal buffer attached, re-allocating\n");
337                 freeInternalBuffer();
338         }
339
340         m_buffer=calloc(m_buffersize,event_size);
341         if (!m_buffer) {
342                 debugFatal("could not allocate internal buffer\n");
343                 m_buffersize=0;
344                 return false;
345         }
346
347         return true;
348 }
349
350 void Port::freeInternalBuffer() {
351         debugOutput(DEBUG_LEVEL_VERBOSE,
352                     "Freeing internal buffer (%s)\n",m_Name.c_str());
353
354         if(m_buffer) {
355                 free(m_buffer);
356                 m_buffer=0;
357         }
358 }
359
360 bool Port::allocateInternalRingBuffer() {
361         int event_size=getEventSize();
362        
363         debugOutput(DEBUG_LEVEL_VERBOSE,
364                     "Allocating internal buffer of %d events with size %d (%s)\n",
365                     m_buffersize, event_size, m_Name.c_str());
366
367         if(m_ringbuffer) {
368                 debugWarning("already has an internal ringbuffer attached, re-allocating\n");
369                 freeInternalRingBuffer();
370         }
371
372         m_ringbuffer=freebob_ringbuffer_create(m_buffersize * event_size);
373         if (!m_ringbuffer) {
374                 debugFatal("could not allocate internal ringbuffer\n");
375                 m_buffersize=0;
376                 return false;
377         }
378
379         return true;
380 }
381
382 void Port::freeInternalRingBuffer() {
383         debugOutput(DEBUG_LEVEL_VERBOSE,
384                     "Freeing internal ringbuffer (%s)\n",m_Name.c_str());
385
386         if(m_ringbuffer) {
387                 freebob_ringbuffer_free(m_ringbuffer);
388                 m_ringbuffer=0;
389         }
390 }
391
392 }
Note: See TracBrowser for help on using the browser.