From 42995d7bf396933ee60c5f89c354ea89cf13df0d Mon Sep 17 00:00:00 2001 From: tpearson Date: Tue, 5 Jan 2010 00:01:18 +0000 Subject: Copy of aRts for Trinity modifications git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/dependencies/arts@1070145 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- COPYING | 347 + COPYING.LIB | 486 + INSTALL | 176 + Makefile.am.in | 32 + Makefile.cvs | 22 + arts.lsm | 11 + artsc/Makefile.am | 32 + artsc/artsc-config.in | 56 + artsc/artsc.c | 226 + artsc/artsc.h | 246 + artsc/artsc_export.h.in | 52 + artsc/artscbackend.cc | 805 ++ artsc/artsdsp.c | 675 ++ artsc/artsdsp.in | 106 + artsc/stdioemu.c | 96 + configure.in.bot | 11 + configure.in.in | 851 ++ doc/Makefile.am | 1 + doc/NEWS | 58 + doc/README | 5 + doc/TODO | 215 + examples/Makefile.am | 97 + examples/aggregation.idl | 27 + examples/artsccat.c | 115 + examples/artscmt.c | 143 + examples/artscrec.c | 115 + examples/artsctest.c | 72 + examples/catfile.cc | 55 + examples/dcasttest.cc | 72 + examples/flow.cc | 56 + examples/hello.idl | 41 + examples/hello_impl.cc | 76 + examples/hello_impl.h | 51 + examples/helloclient.cc | 76 + examples/hellodynamic.cc | 94 + examples/hellodynamic2.cc | 124 + examples/hellomain.cc | 77 + examples/helloserver.cc | 52 + examples/irdemo.cc | 155 + examples/playtofile.idl | 41 + examples/playtofile_impl.cc | 99 + examples/playtofile_main.cc | 147 + examples/referenceinfo.cc | 57 + examples/streamsound.cc | 106 + examples/testaggregation.cc | 73 + examples/testasubsys.cc | 142 + examples/testdhandle.cc | 115 + examples/testthreads.cc | 64 + examples/x11commtest.cc | 76 + flow/Makefile.am | 49 + flow/artsflow.idl | 566 ++ flow/asyncschedule.cc | 553 ++ flow/asyncschedule.h | 134 + flow/audioio.cc | 165 + flow/audioio.h | 145 + flow/audioioaix.cc | 390 + flow/audioioalsa.cc | 561 ++ flow/audioioalsa9.cc | 590 ++ flow/audioiocsl.cc | 640 ++ flow/audioioesd.cc | 231 + flow/audioiojack.cc | 346 + flow/audioiolibaudioio.cc | 236 + flow/audioiomas.cc | 619 ++ flow/audioionas.cc | 260 + flow/audioionull.cc | 184 + flow/audioiooss.cc | 485 + flow/audioioossthreaded.cc | 681 ++ flow/audioiosgi.cc | 274 + flow/audioiosun.cc | 442 + flow/audiomanager_impl.cc | 325 + flow/audiosubsys.cc | 645 ++ flow/audiosubsys.h | 236 + flow/audiotobytestream_impl.cc | 223 + flow/bufferqueue.h | 148 + flow/bus.cc | 367 + flow/bus.h | 76 + flow/bytestreamtoaudio_impl.cc | 119 + flow/cache.cc | 274 + flow/cache.h | 92 + flow/cachedwav.h | 81 + flow/convert.cc | 418 + flow/convert.h | 164 + flow/cpuinfo.cc | 232 + flow/cpuinfo.h | 72 + flow/datahandle_impl.cc | 499 + flow/fft.c | 32 + flow/fft.h | 32 + flow/gsl/Makefile.am | 24 + flow/gsl/arts-patches | 73 + flow/gsl/configure.in.in | 224 + flow/gsl/dummy.cc | 3 + flow/gsl/gbsearcharray.h | 292 + flow/gsl/gsl-fftconf.sh | 468 + flow/gsl/gsl-fftgen.pl | 810 ++ flow/gsl/gsl-iplan.txt | 57 + flow/gsl/gsl-mplan.txt | 226 + flow/gsl/gsl.3 | 822 ++ flow/gsl/gsl.gnuplot | 5 + flow/gsl/gslarrows | 30 + flow/gsl/gslartsthreads.cc | 205 + flow/gsl/gslartsthreads.h | 102 + flow/gsl/gslcommon.c | 1651 ++++ flow/gsl/gslcommon.h | 293 + flow/gsl/gslconfig.h.in | 11 + flow/gsl/gslconvert.c | 57 + flow/gsl/gslconvert.h | 43 + flow/gsl/gsldatacache.c | 633 ++ flow/gsl/gsldatacache.h | 87 + flow/gsl/gsldatahandle-lbuffer.c | 11 + flow/gsl/gsldatahandle-mad.c | 711 ++ flow/gsl/gsldatahandle-mad.h | 42 + flow/gsl/gsldatahandle-vorbis.c | 376 + flow/gsl/gsldatahandle-vorbis.h | 41 + flow/gsl/gsldatahandle.c | 1241 +++ flow/gsl/gsldatahandle.h | 143 + flow/gsl/gsldatautils.c | 462 + flow/gsl/gsldatautils.h | 909 ++ flow/gsl/gsldefs.h | 136 + flow/gsl/gslengine.c | 753 ++ flow/gsl/gslengine.h | 206 + flow/gsl/gslfft.c | 9052 +++++++++++++++++ flow/gsl/gslfft.h | 126 + flow/gsl/gslffttest.c | 435 + flow/gsl/gslfilehash.c | 464 + flow/gsl/gslfilehash.h | 77 + flow/gsl/gslfilter.c | 1379 +++ flow/gsl/gslfilter.h | 281 + flow/gsl/gslglib.c | 2400 +++++ flow/gsl/gslglib.h | 858 ++ flow/gsl/gslglibhash.cc | 151 + flow/gsl/gslglibhashtest.cc | 123 + flow/gsl/gslieee754.h | 246 + flow/gsl/gslincluder.c | 13420 ++++++++++++++++++++++++++ flow/gsl/gslloader-gslwave.c | 701 ++ flow/gsl/gslloader-mad.c | 210 + flow/gsl/gslloader-oggvorbis.c | 178 + flow/gsl/gslloader-wav.c | 442 + flow/gsl/gslloader.c | 335 + flow/gsl/gslloader.h | 136 + flow/gsl/gslmagic.c | 711 ++ flow/gsl/gslmagic.h | 72 + flow/gsl/gslmakefile.inc | 87 + flow/gsl/gslmath.c | 1085 +++ flow/gsl/gslmath.h | 518 + flow/gsl/gslmathtest.c | 334 + flow/gsl/gslopmaster.c | 783 ++ flow/gsl/gslopmaster.h | 42 + flow/gsl/gslopnode.h | 247 + flow/gsl/gslopschedule.c | 582 ++ flow/gsl/gslopschedule.h | 79 + flow/gsl/gsloputil.c | 721 ++ flow/gsl/gsloputil.h | 86 + flow/gsl/gsloscillator-aux.c | 214 + flow/gsl/gsloscillator.c | 219 + flow/gsl/gsloscillator.h | 84 + flow/gsl/gslosctable.c | 626 ++ flow/gsl/gslosctable.h | 104 + flow/gsl/gslsignal.c | 258 + flow/gsl/gslsignal.h | 343 + flow/gsl/gsltests.c | 650 ++ flow/gsl/gslwave.header | Bin 0 -> 3342 bytes flow/gsl/gslwavechunk.c | 812 ++ flow/gsl/gslwavechunk.h | 129 + flow/gsl/gslwaveloader.c | 2 + flow/gsl/gslwaveloader.h | 6 + flow/gsl/gslwaveosc-aux.c | 249 + flow/gsl/gslwaveosc.c | 376 + flow/gsl/gslwaveosc.h | 96 + flow/gsl/gslwchunk.c | 279 + flow/gslpp/Makefile.am | 7 + flow/gslpp/datahandle.cpp | 412 + flow/gslpp/datahandle.h | 220 + flow/gslschedule.cc | 1195 +++ flow/gslschedule.h | 262 + flow/mcopclass/DataHandlePlay.mcopclass | 2 + flow/mcopclass/Makefile.am | 15 + flow/mcopclass/Synth_ADD.mcopclass | 3 + flow/mcopclass/Synth_AMAN_PLAY.mcopclass | 3 + flow/mcopclass/Synth_AMAN_RECORD.mcopclass | 3 + flow/mcopclass/Synth_BUS_DOWNLINK.mcopclass | 3 + flow/mcopclass/Synth_BUS_UPLINK.mcopclass | 3 + flow/mcopclass/Synth_FREQUENCY.mcopclass | 3 + flow/mcopclass/Synth_MUL.mcopclass | 3 + flow/mcopclass/Synth_MULTI_ADD.mcopclass | 3 + flow/mcopclass/Synth_PLAY.mcopclass | 3 + flow/mcopclass/Synth_PLAY_WAV.mcopclass | 3 + flow/mcopclass/Synth_RECORD.mcopclass | 3 + flow/mcopclass/Synth_WAVE_SIN.mcopclass | 3 + flow/mcopclass/WaveDataHandle.mcopclass | 2 + flow/pipebuffer.cc | 166 + flow/pipebuffer.h | 75 + flow/resample.cc | 305 + flow/resample.h | 167 + flow/stdsynthmodule.cc | 92 + flow/stdsynthmodule.h | 65 + flow/stereoeffectstack_impl.cc | 179 + flow/stereofftscope_impl.cc | 131 + flow/stereovolumecontrol_impl.cc | 197 + flow/synth_add_impl.cc | 44 + flow/synth_frequency_impl.cc | 70 + flow/synth_mul_impl.cc | 44 + flow/synth_multi_add_impl.cc | 64 + flow/synth_play_impl.cc | 285 + flow/synth_play_wav_impl.cc | 579 ++ flow/synth_record_impl.cc | 184 + flow/synth_wave_sin_impl.cc | 44 + flow/synthschedule.h | 36 + flow/virtualports.cc | 491 + flow/virtualports.h | 87 + gmcop/Makefile.am | 10 + gmcop/giomanager.cc | 506 + gmcop/giomanager.h | 128 + mcop/Makefile.am | 33 + mcop/anyref.cc | 310 + mcop/anyref.h | 146 + mcop/arts_export.h.in | 53 + mcop/asyncstream.cc | 46 + mcop/asyncstream.h | 103 + mcop/buffer.cc | 386 + mcop/buffer.h | 104 + mcop/common.h | 141 + mcop/connect.cc | 149 + mcop/connect.h | 55 + mcop/connection.cc | 196 + mcop/connection.h | 100 + mcop/core.cc | 3191 ++++++ mcop/core.h | 1561 +++ mcop/core.idl | 715 ++ mcop/datapacket.cc | 65 + mcop/datapacket.h | 230 + mcop/debug.cc | 821 ++ mcop/debug.h | 138 + mcop/delayedreturn.cc | 71 + mcop/delayedreturn.h | 102 + mcop/dispatcher.cc | 1090 +++ mcop/dispatcher.h | 265 + mcop/dynamicrequest.cc | 152 + mcop/dynamicrequest.h | 133 + mcop/dynamicskeleton.cc | 204 + mcop/dynamicskeleton.h | 163 + mcop/extensionloader.cc | 116 + mcop/extensionloader.h | 59 + mcop/factory.cc | 36 + mcop/factory.h | 69 + mcop/flowsystem.cc | 180 + mcop/flowsystem.h | 147 + mcop/idlfilereg.cc | 44 + mcop/idlfilereg.h | 51 + mcop/ifacerepo_impl.cc | 305 + mcop/ifacerepo_impl.h | 98 + mcop/iomanager.cc | 494 + mcop/iomanager.h | 214 + mcop/loopback.cc | 57 + mcop/loopback.h | 51 + mcop/mcopconfig.cc | 67 + mcop/mcopconfig.h | 55 + mcop/mcoputils.cc | 574 ++ mcop/mcoputils.h | 97 + mcop/md5.c | 197 + mcop/md5.h | 45 + mcop/md5auth.cc | 213 + mcop/md5auth.h | 105 + mcop/namedstore.h | 125 + mcop/notification.cc | 101 + mcop/notification.h | 87 + mcop/object.cc | 1528 +++ mcop/object.h | 390 + mcop/objectmanager.cc | 289 + mcop/objectmanager.h | 75 + mcop/pool.h | 89 + mcop/reference.cc | 32 + mcop/reference.h | 349 + mcop/referenceclean.cc | 87 + mcop/referenceclean.h | 60 + mcop/socketconnection.cc | 205 + mcop/socketconnection.h | 64 + mcop/startupmanager.cc | 150 + mcop/startupmanager.h | 75 + mcop/tcpconnection.cc | 152 + mcop/tcpconnection.h | 43 + mcop/tcpserver.cc | 193 + mcop/tcpserver.h | 61 + mcop/thread.cc | 169 + mcop/thread.h | 375 + mcop/tmpglobalcomm.cc | 82 + mcop/trader_impl.cc | 345 + mcop/type.cc | 31 + mcop/type.h | 85 + mcop/unixconnection.cc | 114 + mcop/unixconnection.h | 43 + mcop/unixserver.cc | 151 + mcop/unixserver.h | 59 + mcop/weakreference.h | 131 + mcop_mt/Makefile.am | 9 + mcop_mt/threads_posix.cc | 399 + mcopidl/Makefile.am | 19 + mcopidl/mcopidl.cc | 2645 +++++ mcopidl/namespace.cc | 208 + mcopidl/namespace.h | 91 + mcopidl/scanner.cc | 2090 ++++ mcopidl/scanner.ll | 183 + mcopidl/yacc.cc | 1507 +++ mcopidl/yacc.cc.h | 75 + mcopidl/yacc.yy | 451 + qtmcop/Makefile.am | 14 + qtmcop/qiomanager.cc | 299 + qtmcop/qiomanager.h | 106 + qtmcop/qiomanager_p.h | 77 + soundserver/FileInputStream.mcopclass | 5 + soundserver/GSLPlayObject.mcopclass | 7 + soundserver/Makefile.am | 122 + soundserver/WavPlayObject.mcopclass | 7 + soundserver/artscat.cc | 244 + soundserver/artsd.cc | 376 + soundserver/artsplay.cc | 77 + soundserver/artsrec.cc | 194 + soundserver/artsshell.cc | 671 ++ soundserver/artsversion-new.h.in | 31 + soundserver/artswrapper.c | 120 + soundserver/cpuusage.cc | 137 + soundserver/cpuusage.h | 53 + soundserver/crashhandler.cc | 236 + soundserver/crashhandler.h | 131 + soundserver/fileinputstream_impl.cc | 193 + soundserver/gslplayobject_impl.cc | 235 + soundserver/kmedia2.idl | 242 + soundserver/samplestorage_impl.cc | 202 + soundserver/simplesoundserver_impl.cc | 453 + soundserver/simplesoundserver_impl.h | 148 + soundserver/soundserver.idl | 294 + soundserver/soundserver_impl.cc | 90 + soundserver/soundserver_impl.h | 46 + soundserver/soundserverstartup_impl.cc | 99 + soundserver/soundserverstartup_impl.h | 49 + soundserver/soundserverv2_impl.cc | 386 + soundserver/soundserverv2_impl.h | 71 + soundserver/stdoutwriter_impl.cc | 52 + soundserver/tradercheck.cc | 213 + soundserver/tradercheck.h | 50 + soundserver/wavplayobject_impl.cc | 172 + tests/Makefile.am | 44 + tests/README.test | 72 + tests/remotetest.idl | 11 + tests/test.h | 130 + tests/testanyref.cc | 97 + tests/testbuffer.cc | 139 + tests/testchangenotify.cc | 195 + tests/testdispatcher.cc | 41 + tests/testflowsystem.cc | 83 + tests/testifacerepo.cc | 84 + tests/testnotification.cc | 146 + tests/testremote.cc | 176 + tests/testwrapper.cc | 211 + tests/value.idl | 18 + tests/value_impl.cc | 94 + tests/wrapper.idl | 27 + x11/Makefile.am | 29 + x11/X11GlobalComm.mcopclass | 3 + x11/x11globalcomm.idl | 30 + x11/x11globalcomm_impl.cc | 184 + 360 files changed, 111698 insertions(+) create mode 100644 COPYING create mode 100644 COPYING.LIB create mode 100644 INSTALL create mode 100644 Makefile.am.in create mode 100644 Makefile.cvs create mode 100644 arts.lsm create mode 100644 artsc/Makefile.am create mode 100755 artsc/artsc-config.in create mode 100644 artsc/artsc.c create mode 100644 artsc/artsc.h create mode 100644 artsc/artsc_export.h.in create mode 100644 artsc/artscbackend.cc create mode 100644 artsc/artsdsp.c create mode 100755 artsc/artsdsp.in create mode 100644 artsc/stdioemu.c create mode 100644 configure.in.bot create mode 100644 configure.in.in create mode 100644 doc/Makefile.am create mode 100644 doc/NEWS create mode 100644 doc/README create mode 100644 doc/TODO create mode 100644 examples/Makefile.am create mode 100644 examples/aggregation.idl create mode 100644 examples/artsccat.c create mode 100644 examples/artscmt.c create mode 100644 examples/artscrec.c create mode 100644 examples/artsctest.c create mode 100644 examples/catfile.cc create mode 100644 examples/dcasttest.cc create mode 100644 examples/flow.cc create mode 100644 examples/hello.idl create mode 100644 examples/hello_impl.cc create mode 100644 examples/hello_impl.h create mode 100644 examples/helloclient.cc create mode 100644 examples/hellodynamic.cc create mode 100644 examples/hellodynamic2.cc create mode 100644 examples/hellomain.cc create mode 100644 examples/helloserver.cc create mode 100644 examples/irdemo.cc create mode 100644 examples/playtofile.idl create mode 100644 examples/playtofile_impl.cc create mode 100644 examples/playtofile_main.cc create mode 100644 examples/referenceinfo.cc create mode 100644 examples/streamsound.cc create mode 100644 examples/testaggregation.cc create mode 100644 examples/testasubsys.cc create mode 100644 examples/testdhandle.cc create mode 100644 examples/testthreads.cc create mode 100644 examples/x11commtest.cc create mode 100644 flow/Makefile.am create mode 100644 flow/artsflow.idl create mode 100644 flow/asyncschedule.cc create mode 100644 flow/asyncschedule.h create mode 100644 flow/audioio.cc create mode 100644 flow/audioio.h create mode 100644 flow/audioioaix.cc create mode 100644 flow/audioioalsa.cc create mode 100644 flow/audioioalsa9.cc create mode 100644 flow/audioiocsl.cc create mode 100644 flow/audioioesd.cc create mode 100644 flow/audioiojack.cc create mode 100644 flow/audioiolibaudioio.cc create mode 100644 flow/audioiomas.cc create mode 100644 flow/audioionas.cc create mode 100644 flow/audioionull.cc create mode 100644 flow/audioiooss.cc create mode 100644 flow/audioioossthreaded.cc create mode 100644 flow/audioiosgi.cc create mode 100644 flow/audioiosun.cc create mode 100644 flow/audiomanager_impl.cc create mode 100644 flow/audiosubsys.cc create mode 100644 flow/audiosubsys.h create mode 100644 flow/audiotobytestream_impl.cc create mode 100644 flow/bufferqueue.h create mode 100644 flow/bus.cc create mode 100644 flow/bus.h create mode 100644 flow/bytestreamtoaudio_impl.cc create mode 100644 flow/cache.cc create mode 100644 flow/cache.h create mode 100644 flow/cachedwav.h create mode 100644 flow/convert.cc create mode 100644 flow/convert.h create mode 100644 flow/cpuinfo.cc create mode 100644 flow/cpuinfo.h create mode 100644 flow/datahandle_impl.cc create mode 100644 flow/fft.c create mode 100644 flow/fft.h create mode 100644 flow/gsl/Makefile.am create mode 100644 flow/gsl/arts-patches create mode 100644 flow/gsl/configure.in.in create mode 100644 flow/gsl/dummy.cc create mode 100644 flow/gsl/gbsearcharray.h create mode 100755 flow/gsl/gsl-fftconf.sh create mode 100755 flow/gsl/gsl-fftgen.pl create mode 100644 flow/gsl/gsl-iplan.txt create mode 100644 flow/gsl/gsl-mplan.txt create mode 100644 flow/gsl/gsl.3 create mode 100644 flow/gsl/gsl.gnuplot create mode 100644 flow/gsl/gslarrows create mode 100644 flow/gsl/gslartsthreads.cc create mode 100644 flow/gsl/gslartsthreads.h create mode 100644 flow/gsl/gslcommon.c create mode 100644 flow/gsl/gslcommon.h create mode 100644 flow/gsl/gslconfig.h.in create mode 100644 flow/gsl/gslconvert.c create mode 100644 flow/gsl/gslconvert.h create mode 100644 flow/gsl/gsldatacache.c create mode 100644 flow/gsl/gsldatacache.h create mode 100644 flow/gsl/gsldatahandle-lbuffer.c create mode 100644 flow/gsl/gsldatahandle-mad.c create mode 100644 flow/gsl/gsldatahandle-mad.h create mode 100644 flow/gsl/gsldatahandle-vorbis.c create mode 100644 flow/gsl/gsldatahandle-vorbis.h create mode 100644 flow/gsl/gsldatahandle.c create mode 100644 flow/gsl/gsldatahandle.h create mode 100644 flow/gsl/gsldatautils.c create mode 100644 flow/gsl/gsldatautils.h create mode 100644 flow/gsl/gsldefs.h create mode 100644 flow/gsl/gslengine.c create mode 100644 flow/gsl/gslengine.h create mode 100644 flow/gsl/gslfft.c create mode 100644 flow/gsl/gslfft.h create mode 100644 flow/gsl/gslffttest.c create mode 100644 flow/gsl/gslfilehash.c create mode 100644 flow/gsl/gslfilehash.h create mode 100644 flow/gsl/gslfilter.c create mode 100644 flow/gsl/gslfilter.h create mode 100644 flow/gsl/gslglib.c create mode 100644 flow/gsl/gslglib.h create mode 100644 flow/gsl/gslglibhash.cc create mode 100644 flow/gsl/gslglibhashtest.cc create mode 100644 flow/gsl/gslieee754.h create mode 100644 flow/gsl/gslincluder.c create mode 100644 flow/gsl/gslloader-gslwave.c create mode 100644 flow/gsl/gslloader-mad.c create mode 100644 flow/gsl/gslloader-oggvorbis.c create mode 100644 flow/gsl/gslloader-wav.c create mode 100644 flow/gsl/gslloader.c create mode 100644 flow/gsl/gslloader.h create mode 100644 flow/gsl/gslmagic.c create mode 100644 flow/gsl/gslmagic.h create mode 100644 flow/gsl/gslmakefile.inc create mode 100644 flow/gsl/gslmath.c create mode 100644 flow/gsl/gslmath.h create mode 100644 flow/gsl/gslmathtest.c create mode 100644 flow/gsl/gslopmaster.c create mode 100644 flow/gsl/gslopmaster.h create mode 100644 flow/gsl/gslopnode.h create mode 100644 flow/gsl/gslopschedule.c create mode 100644 flow/gsl/gslopschedule.h create mode 100644 flow/gsl/gsloputil.c create mode 100644 flow/gsl/gsloputil.h create mode 100644 flow/gsl/gsloscillator-aux.c create mode 100644 flow/gsl/gsloscillator.c create mode 100644 flow/gsl/gsloscillator.h create mode 100644 flow/gsl/gslosctable.c create mode 100644 flow/gsl/gslosctable.h create mode 100644 flow/gsl/gslsignal.c create mode 100644 flow/gsl/gslsignal.h create mode 100644 flow/gsl/gsltests.c create mode 100644 flow/gsl/gslwave.header create mode 100644 flow/gsl/gslwavechunk.c create mode 100644 flow/gsl/gslwavechunk.h create mode 100644 flow/gsl/gslwaveloader.c create mode 100644 flow/gsl/gslwaveloader.h create mode 100644 flow/gsl/gslwaveosc-aux.c create mode 100644 flow/gsl/gslwaveosc.c create mode 100644 flow/gsl/gslwaveosc.h create mode 100644 flow/gsl/gslwchunk.c create mode 100644 flow/gslpp/Makefile.am create mode 100644 flow/gslpp/datahandle.cpp create mode 100644 flow/gslpp/datahandle.h create mode 100644 flow/gslschedule.cc create mode 100644 flow/gslschedule.h create mode 100644 flow/mcopclass/DataHandlePlay.mcopclass create mode 100644 flow/mcopclass/Makefile.am create mode 100644 flow/mcopclass/Synth_ADD.mcopclass create mode 100644 flow/mcopclass/Synth_AMAN_PLAY.mcopclass create mode 100644 flow/mcopclass/Synth_AMAN_RECORD.mcopclass create mode 100644 flow/mcopclass/Synth_BUS_DOWNLINK.mcopclass create mode 100644 flow/mcopclass/Synth_BUS_UPLINK.mcopclass create mode 100644 flow/mcopclass/Synth_FREQUENCY.mcopclass create mode 100644 flow/mcopclass/Synth_MUL.mcopclass create mode 100644 flow/mcopclass/Synth_MULTI_ADD.mcopclass create mode 100644 flow/mcopclass/Synth_PLAY.mcopclass create mode 100644 flow/mcopclass/Synth_PLAY_WAV.mcopclass create mode 100644 flow/mcopclass/Synth_RECORD.mcopclass create mode 100644 flow/mcopclass/Synth_WAVE_SIN.mcopclass create mode 100644 flow/mcopclass/WaveDataHandle.mcopclass create mode 100644 flow/pipebuffer.cc create mode 100644 flow/pipebuffer.h create mode 100644 flow/resample.cc create mode 100644 flow/resample.h create mode 100644 flow/stdsynthmodule.cc create mode 100644 flow/stdsynthmodule.h create mode 100644 flow/stereoeffectstack_impl.cc create mode 100644 flow/stereofftscope_impl.cc create mode 100644 flow/stereovolumecontrol_impl.cc create mode 100644 flow/synth_add_impl.cc create mode 100644 flow/synth_frequency_impl.cc create mode 100644 flow/synth_mul_impl.cc create mode 100644 flow/synth_multi_add_impl.cc create mode 100644 flow/synth_play_impl.cc create mode 100644 flow/synth_play_wav_impl.cc create mode 100644 flow/synth_record_impl.cc create mode 100644 flow/synth_wave_sin_impl.cc create mode 100644 flow/synthschedule.h create mode 100644 flow/virtualports.cc create mode 100644 flow/virtualports.h create mode 100644 gmcop/Makefile.am create mode 100644 gmcop/giomanager.cc create mode 100644 gmcop/giomanager.h create mode 100644 mcop/Makefile.am create mode 100644 mcop/anyref.cc create mode 100644 mcop/anyref.h create mode 100644 mcop/arts_export.h.in create mode 100644 mcop/asyncstream.cc create mode 100644 mcop/asyncstream.h create mode 100644 mcop/buffer.cc create mode 100644 mcop/buffer.h create mode 100644 mcop/common.h create mode 100644 mcop/connect.cc create mode 100644 mcop/connect.h create mode 100644 mcop/connection.cc create mode 100644 mcop/connection.h create mode 100644 mcop/core.cc create mode 100644 mcop/core.h create mode 100644 mcop/core.idl create mode 100644 mcop/datapacket.cc create mode 100644 mcop/datapacket.h create mode 100644 mcop/debug.cc create mode 100644 mcop/debug.h create mode 100644 mcop/delayedreturn.cc create mode 100644 mcop/delayedreturn.h create mode 100644 mcop/dispatcher.cc create mode 100644 mcop/dispatcher.h create mode 100644 mcop/dynamicrequest.cc create mode 100644 mcop/dynamicrequest.h create mode 100644 mcop/dynamicskeleton.cc create mode 100644 mcop/dynamicskeleton.h create mode 100644 mcop/extensionloader.cc create mode 100644 mcop/extensionloader.h create mode 100644 mcop/factory.cc create mode 100644 mcop/factory.h create mode 100644 mcop/flowsystem.cc create mode 100644 mcop/flowsystem.h create mode 100644 mcop/idlfilereg.cc create mode 100644 mcop/idlfilereg.h create mode 100644 mcop/ifacerepo_impl.cc create mode 100644 mcop/ifacerepo_impl.h create mode 100644 mcop/iomanager.cc create mode 100644 mcop/iomanager.h create mode 100644 mcop/loopback.cc create mode 100644 mcop/loopback.h create mode 100644 mcop/mcopconfig.cc create mode 100644 mcop/mcopconfig.h create mode 100644 mcop/mcoputils.cc create mode 100644 mcop/mcoputils.h create mode 100644 mcop/md5.c create mode 100644 mcop/md5.h create mode 100644 mcop/md5auth.cc create mode 100644 mcop/md5auth.h create mode 100644 mcop/namedstore.h create mode 100644 mcop/notification.cc create mode 100644 mcop/notification.h create mode 100644 mcop/object.cc create mode 100644 mcop/object.h create mode 100644 mcop/objectmanager.cc create mode 100644 mcop/objectmanager.h create mode 100644 mcop/pool.h create mode 100644 mcop/reference.cc create mode 100644 mcop/reference.h create mode 100644 mcop/referenceclean.cc create mode 100644 mcop/referenceclean.h create mode 100644 mcop/socketconnection.cc create mode 100644 mcop/socketconnection.h create mode 100644 mcop/startupmanager.cc create mode 100644 mcop/startupmanager.h create mode 100644 mcop/tcpconnection.cc create mode 100644 mcop/tcpconnection.h create mode 100644 mcop/tcpserver.cc create mode 100644 mcop/tcpserver.h create mode 100644 mcop/thread.cc create mode 100644 mcop/thread.h create mode 100644 mcop/tmpglobalcomm.cc create mode 100644 mcop/trader_impl.cc create mode 100644 mcop/type.cc create mode 100644 mcop/type.h create mode 100644 mcop/unixconnection.cc create mode 100644 mcop/unixconnection.h create mode 100644 mcop/unixserver.cc create mode 100644 mcop/unixserver.h create mode 100644 mcop/weakreference.h create mode 100644 mcop_mt/Makefile.am create mode 100644 mcop_mt/threads_posix.cc create mode 100644 mcopidl/Makefile.am create mode 100644 mcopidl/mcopidl.cc create mode 100644 mcopidl/namespace.cc create mode 100644 mcopidl/namespace.h create mode 100644 mcopidl/scanner.cc create mode 100644 mcopidl/scanner.ll create mode 100644 mcopidl/yacc.cc create mode 100644 mcopidl/yacc.cc.h create mode 100644 mcopidl/yacc.yy create mode 100644 qtmcop/Makefile.am create mode 100644 qtmcop/qiomanager.cc create mode 100644 qtmcop/qiomanager.h create mode 100644 qtmcop/qiomanager_p.h create mode 100644 soundserver/FileInputStream.mcopclass create mode 100644 soundserver/GSLPlayObject.mcopclass create mode 100644 soundserver/Makefile.am create mode 100644 soundserver/WavPlayObject.mcopclass create mode 100644 soundserver/artscat.cc create mode 100644 soundserver/artsd.cc create mode 100644 soundserver/artsplay.cc create mode 100644 soundserver/artsrec.cc create mode 100644 soundserver/artsshell.cc create mode 100644 soundserver/artsversion-new.h.in create mode 100644 soundserver/artswrapper.c create mode 100644 soundserver/cpuusage.cc create mode 100644 soundserver/cpuusage.h create mode 100644 soundserver/crashhandler.cc create mode 100644 soundserver/crashhandler.h create mode 100644 soundserver/fileinputstream_impl.cc create mode 100644 soundserver/gslplayobject_impl.cc create mode 100644 soundserver/kmedia2.idl create mode 100644 soundserver/samplestorage_impl.cc create mode 100644 soundserver/simplesoundserver_impl.cc create mode 100644 soundserver/simplesoundserver_impl.h create mode 100644 soundserver/soundserver.idl create mode 100644 soundserver/soundserver_impl.cc create mode 100644 soundserver/soundserver_impl.h create mode 100644 soundserver/soundserverstartup_impl.cc create mode 100644 soundserver/soundserverstartup_impl.h create mode 100644 soundserver/soundserverv2_impl.cc create mode 100644 soundserver/soundserverv2_impl.h create mode 100644 soundserver/stdoutwriter_impl.cc create mode 100644 soundserver/tradercheck.cc create mode 100644 soundserver/tradercheck.h create mode 100644 soundserver/wavplayobject_impl.cc create mode 100644 tests/Makefile.am create mode 100644 tests/README.test create mode 100644 tests/remotetest.idl create mode 100644 tests/test.h create mode 100644 tests/testanyref.cc create mode 100644 tests/testbuffer.cc create mode 100644 tests/testchangenotify.cc create mode 100644 tests/testdispatcher.cc create mode 100644 tests/testflowsystem.cc create mode 100644 tests/testifacerepo.cc create mode 100644 tests/testnotification.cc create mode 100644 tests/testremote.cc create mode 100644 tests/testwrapper.cc create mode 100644 tests/value.idl create mode 100644 tests/value_impl.cc create mode 100644 tests/wrapper.idl create mode 100644 x11/Makefile.am create mode 100644 x11/X11GlobalComm.mcopclass create mode 100644 x11/x11globalcomm.idl create mode 100644 x11/x11globalcomm_impl.cc diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..127b32a --- /dev/null +++ b/COPYING @@ -0,0 +1,347 @@ +NOTE! The GPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the arts programs) are copyrighted +by the authors who actually wrote it. + +--------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000..3fb952c --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,486 @@ +NOTE! The LGPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the arts libraries) are copyrighted +by the authors who actually wrote it. + +--------------------------------------------------------------------------- + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..f8bad0c --- /dev/null +++ b/INSTALL @@ -0,0 +1,176 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes a while. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/kde/bin', `/usr/local/kde/lib', etc. You can specify an +installation prefix other than `/usr/local/kde' by giving `configure' +the option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/Makefile.am.in b/Makefile.am.in new file mode 100644 index 0000000..e47ac1d --- /dev/null +++ b/Makefile.am.in @@ -0,0 +1,32 @@ +# This file is part of the KDE libraries +# Copyright (C) 1996-1997 Matthias Kalle Dalheimer (kalle@kde.org) +# (C) 1997,1998 Stephan Kulow (coolo@kde.org) + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public License +# along with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +include admin/deps.am + +$(top_srcdir)/acinclude.m4: $(top_srcdir)/libltdl/ltdl.m4 + +AUTOMAKE_OPTIONS = foreign 1.6.1 +COMPILE_FIRST = libltdl mcop mcopidl flow mcop_mt soundserver artsc examples tests doc +EXTRA_DIST = admin + +dist-hook: + cd $(top_distdir) && perl admin/am_edit -padmin + +#DIST_SUBDIRS = mcop mcop_mt mcopidl flow soundserver artsc examples tests doc +# gmcop x11 qtmcop kde knotify message diff --git a/Makefile.cvs b/Makefile.cvs new file mode 100644 index 0000000..cf82c8d --- /dev/null +++ b/Makefile.cvs @@ -0,0 +1,22 @@ + +all: + @echo "This Makefile is only for the CVS repository" + @echo "This will be deleted before making the distribution" + @echo "" + @if test ! -d admin; then \ + echo "Please recheckout this module!" ;\ + echo "for cvs: use checkout once and after that update again" ;\ + echo "for cvsup: checkout kde-common from cvsup and" ;\ + echo " link kde-common/admin to ./admin" ;\ + exit 1 ;\ + fi + @if test ! -d libltdl; then \ + echo "Please recheckout this module!" ;\ + echo "for cvs: use checkout once and after that update again" ;\ + echo "for cvsup: checkout kdelibs from cvsup and" ;\ + echo " cp -a ../kdelibs/libltdl ./libltdl" ;\ + exit 1 ;\ + fi + $(MAKE) -f admin/Makefile.common cvs + +.SILENT: diff --git a/arts.lsm b/arts.lsm new file mode 100644 index 0000000..9fc82e1 --- /dev/null +++ b/arts.lsm @@ -0,0 +1,11 @@ +Begin4 +Title: arts +Version: 1.5.10 +Entered-date: 2008-08-26 +Description: Soundserver for the K Desktop Environment (KDE) +Keywords: KDE X11 desktop Qt +Author: http://bugs.kde.org/ (KDE Bugtracking System) +Primary-site: http://www.kde.org/download/ +Platforms: Unix, Qt +Copying-policy: LGPL, Artistic +End diff --git a/artsc/Makefile.am b/artsc/Makefile.am new file mode 100644 index 0000000..7487633 --- /dev/null +++ b/artsc/Makefile.am @@ -0,0 +1,32 @@ +AM_CFLAGS = -DARTSC_BACKEND='"$(libdir)/libartscbackend.la"' +AM_CPPFLAGS = -DCOMPILING_ARTSC +lib_LTLIBRARIES = libartsc.la libartscbackend.la libartsdsp.la libartsdsp_st.la +FLOWLIBS = $(top_builddir)/flow/libartsflow.la + +INCLUDES = -I$(top_srcdir)/mcop -I$(top_builddir)/mcop -I$(top_srcdir)/flow \ + -I$(top_builddir)/flow -I$(top_builddir)/soundserver \ + -I$(top_srcdir)/libltdl $(all_includes) + +bin_SCRIPTS = artsc-config artsdsp + +libartsdsp_la_SOURCES = artsdsp.c +libartsdsp_la_LDFLAGS = -no-undefined -module $(all_libraries) +libartsdsp_la_LIBADD = libartsc.la + +libartsdsp_st_la_SOURCES = artsc.c artsdsp.c +libartsdsp_st_la_LDFLAGS = -no-undefined -module $(all_libraries) +libartsdsp_st_la_LIBADD = $(top_builddir)/libltdl/libltdlc.la + +libartsc_la_SOURCES = artsc.c +libartsc_la_LDFLAGS = -no-undefined $(USE_THREADS) $(all_libraries) +libartsc_la_LIBADD = $(top_builddir)/libltdl/libltdlc.la $(LIBPTHREAD) + +libartscbackend_la_SOURCES = artscbackend.cc +libartscbackend_la_LDFLAGS = -no-undefined -module $(KDE_RPATH) $(all_libraries) +libartscbackend_la_LIBADD = $(FLOWLIBS) \ + $(top_builddir)/soundserver/libsoundserver_idl.la + +artscincludedir = $(includedir)/artsc +artscinclude_HEADERS = artsc.h artsc_export.h + +artscbackend.lo: $(top_builddir)/soundserver/soundserver.h ../flow/artsflow.h diff --git a/artsc/artsc-config.in b/artsc/artsc-config.in new file mode 100755 index 0000000..8b9b578 --- /dev/null +++ b/artsc/artsc-config.in @@ -0,0 +1,56 @@ +#!/bin/sh + +usage() +{ + echo "usage: $0 [OPTIONS]" +cat << EOH + +options: + [--libs] + [--cflags] + [--version] + [--arts-version] + [--arts-prefix] +EOH + exit 1; +} + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +libdl=@LIBDL@ + +flags="" + +while test $# -gt 0 +do + case $1 in + --libs) + flags="$flags -L$libdir $libdl -lartsc @USE_THREADS@ @LIBPTHREAD@ @GLIB_LDFLAGS@ @GLIB_LIBADD@" + ;; + --cflags) + flags="$flags -I$includedir/artsc @GLIB_CFLAGS@" + ;; + --version) + echo 0.9.5 + ;; + --arts-version) + echo @ARTS_VERSION@ + ;; + --arts-prefix) + echo $prefix + ;; + *) + echo "$0: unknown option $1" + echo + usage + ;; + esac + shift +done + +if test -n "$flags" +then + echo $flags +fi diff --git a/artsc/artsc.c b/artsc/artsc.c new file mode 100644 index 0000000..61a02b6 --- /dev/null +++ b/artsc/artsc.c @@ -0,0 +1,226 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsc.h" +#include "ltdl.h" +#include + +typedef int (*backend_init_ptr)(); +typedef int (*backend_suspend_ptr)(); +typedef int (*backend_suspended_ptr)(); +typedef void (*backend_free_ptr)(); +typedef arts_stream_t (*backend_play_stream_ptr)(int,int,int,const char*); +typedef arts_stream_t (*backend_record_stream_ptr)(int,int,int,const char*); +typedef void (*backend_close_stream_ptr)(arts_stream_t); +typedef int (*backend_read_ptr)(arts_stream_t,void*,int); +typedef int (*backend_write_ptr)(arts_stream_t,const void*,int); +typedef int (*backend_stream_set_ptr)(arts_stream_t, arts_parameter_t, int); +typedef int (*backend_stream_get_ptr)(arts_stream_t, arts_parameter_t); + +static struct arts_backend { + int available; + int refcnt; + lt_dlhandle handle; + + backend_init_ptr init; + backend_suspend_ptr suspend; + backend_suspended_ptr suspended; + backend_free_ptr free; + backend_play_stream_ptr play_stream; + backend_record_stream_ptr record_stream; + backend_close_stream_ptr close_stream; + backend_read_ptr read; + backend_write_ptr write; + backend_stream_set_ptr stream_set; + backend_stream_get_ptr stream_get; +} backend = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + +static void arts_backend_ref() +{ + if(backend.refcnt == 0) + { + lt_dlinit(); + backend.handle = lt_dlopen(ARTSC_BACKEND); + + if(backend.handle) + { + backend.init = (backend_init_ptr) + lt_dlsym(backend.handle, "arts_backend_init"); + backend.suspend = (backend_suspend_ptr) + lt_dlsym(backend.handle, "arts_backend_suspend"); + backend.suspended = (backend_suspended_ptr) + lt_dlsym(backend.handle, "arts_backend_suspended"); + backend.free = (backend_free_ptr) + lt_dlsym(backend.handle, "arts_backend_free"); + backend.play_stream = (backend_play_stream_ptr) + lt_dlsym(backend.handle, "arts_backend_play_stream"); + backend.record_stream = (backend_record_stream_ptr) + lt_dlsym(backend.handle, "arts_backend_record_stream"); + backend.close_stream = (backend_close_stream_ptr) + lt_dlsym(backend.handle, "arts_backend_close_stream"); + backend.write = (backend_write_ptr) + lt_dlsym(backend.handle, "arts_backend_write"); + backend.read = (backend_read_ptr) + lt_dlsym(backend.handle, "arts_backend_read"); + backend.stream_set = (backend_stream_set_ptr) + lt_dlsym(backend.handle, "arts_backend_stream_set"); + backend.stream_get = (backend_stream_get_ptr) + lt_dlsym(backend.handle, "arts_backend_stream_get"); + } + + if(backend.handle && backend.init && backend.free && backend.play_stream + && backend.record_stream && backend.close_stream && backend.write + && backend.read && backend.stream_set && backend.stream_get + && backend.suspend) + backend.available = 1; + else + backend.available = 0; + } + backend.refcnt++; +} + +static void arts_backend_release() +{ + assert(backend.refcnt > 0); + backend.refcnt--; + if(backend.refcnt == 0) + { + if(backend.available) + { + backend.available = 0; + + if(backend.handle) lt_dlclose(backend.handle); + } + lt_dlexit(); + } +} + +int arts_init() +{ + int rc = ARTS_E_NOBACKEND; + + arts_backend_ref(); + if(backend.available) rc = backend.init(); + + /* init failed: the user may not call other arts_xxx functions now */ + if(rc < 0) arts_backend_release(); + + return rc; +} + +int arts_suspend() +{ + int rc = ARTS_E_NOBACKEND; + + if(backend.available) rc = backend.suspend(); + return rc; +} + +int arts_suspended() +{ + int rc = ARTS_E_NOBACKEND; + + if(backend.available && backend.suspended) rc = backend.suspended(); + return rc; +} + +void arts_free() +{ + if(backend.available) + { + backend.free(); + arts_backend_release(); + } +} + +arts_stream_t arts_play_stream(int rate, int bits, int channels, const char *name) +{ + arts_stream_t rc = 0; + + if(backend.available) rc = backend.play_stream(rate,bits,channels,name); + return rc; +} + +arts_stream_t arts_record_stream(int rate, int bits, int channels, const char *name) +{ + arts_stream_t rc = 0; + + if(backend.available) rc = backend.record_stream(rate,bits,channels,name); + return rc; +} + +void arts_close_stream(arts_stream_t stream) +{ + if(backend.available) backend.close_stream(stream); +} + +int arts_read(arts_stream_t stream, void *buffer, int count) +{ + int rc = ARTS_E_NOBACKEND; + + if(backend.available) rc = backend.read(stream,buffer,count); + return rc; +} + +int arts_write(arts_stream_t stream, const void *buffer, int count) +{ + int rc = ARTS_E_NOBACKEND; + + if(backend.available) rc = backend.write(stream,buffer,count); + return rc; +} + +int arts_stream_set(arts_stream_t stream, arts_parameter_t param, int value) +{ + int rc = ARTS_E_NOBACKEND; + + if(backend.available) rc = backend.stream_set(stream,param,value); + return rc; +} + +int arts_stream_get(arts_stream_t stream, arts_parameter_t param) +{ + int rc = ARTS_E_NOBACKEND; + + if(backend.available) rc = backend.stream_get(stream,param); + return rc; +} + +const char *arts_error_text(int errorcode) +{ + switch(errorcode) { + case 0: + return "success"; + case ARTS_E_NOSERVER: + return "can't connect to aRts soundserver"; + case ARTS_E_NOBACKEND: + return "loading the aRts backend \"" + ARTSC_BACKEND "\" failed"; + case ARTS_E_NOIMPL: + return "this aRts function is not yet implemented"; + case ARTS_E_NOINIT: + return "need to use arts_init() before using other functions"; + case ARTS_E_NOSTREAM: + return "you passed no valid aRts stream to a function"; + } + return "unknown arts error happened"; +} diff --git a/artsc/artsc.h b/artsc/artsc.h new file mode 100644 index 0000000..5cdf8f1 --- /dev/null +++ b/artsc/artsc.h @@ -0,0 +1,246 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifndef ARTSC_H +#define ARTSC_H + +#include "artsc_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @libdoc aRts plain C API + * + * The aRts plain C API aims at easily writing/porting plain C apps to the + * arts sound server. What is provided is streaming functionality, in a + * blocking way. So for most apps, you simply remove the few system calls + * that deal with your audio device, and replace them with the appropriate + * arts calls. + */ + +/** + * the type of streams (simply treat these as black boxes) + */ +typedef void *arts_stream_t; + +/* error codes */ + +#define ARTS_E_NOSERVER ( -1 ) +#define ARTS_E_NOBACKEND ( -2 ) +#define ARTS_E_NOSTREAM ( -3 ) +#define ARTS_E_NOINIT ( -4 ) +#define ARTS_E_NOIMPL ( -5 ) + +/** + * the values for stream parameters + * + * @see arts_parameter_t + */ +enum arts_parameter_t_enum { + ARTS_P_BUFFER_SIZE = 1, + ARTS_P_BUFFER_TIME = 2, + ARTS_P_BUFFER_SPACE = 3, + ARTS_P_SERVER_LATENCY = 4, + ARTS_P_TOTAL_LATENCY = 5, + ARTS_P_BLOCKING = 6, + ARTS_P_PACKET_SIZE = 7, + ARTS_P_PACKET_COUNT = 8, + ARTS_P_PACKET_SETTINGS = 9 +}; + +/** + * parameters for streams + * + * @li ARTS_P_BUFFER_SIZE (rw) + * The size of the internal buffers used for streaming to the server - this + * directly affects the latency that will occur. If you never set it + * explicitly, this value defaults to at least 65536 (64kb). Generally, + * it is important to know that the server itself gives some constraints + * which makes buffer sizes below a certain value impossible. So setting + * this parameter will always result in either getting what you wanted, + * or a larger streaming buffer due to server limitations. + * + * @li ARTS_P_BUFFER_TIME (rw) + * The time the buffer used for streaming to the server takes to play in + * milliseconds. This is just a more human readable method to set the buffer + * size, so setting ARTS_P_BUFFER_SIZE affects this parameter and the other + * way round. As aRts chooses reasonable buffer sizes for streaming (rather + * 3*16kb than 40234 bytes), setting this parameter will often end up with + * a slightly larger value than you requested. + * + * @li ARTS_P_BUFFER_SPACE (r) + * The amount of bytes that can be read/written without blocking (depending + * whether this is a record or play stream). As requesting this parameter + * does a few system calls (but no remote invocation) to verify that it is + * up-to-date, don't overuse it. + * + * @li ARTS_P_SERVER_LATENCY (r) + * The amount of latency the server creates (due to hardware buffering) + * in milliseconds. + * + * @li ARTS_P_TOTAL_LATENCY (r) + * The overall latency in milliseconds it takes (at most), from the time + * when you write a byte into a stream, until it gets played on the + * soundcard. This is simply a shortcut to the sum of ARTS_P_BUFFER_TIME + * and ARTS_P_SERVER_LATENCY. + * + * @li ARTS_P_BLOCKING (rw) + * If this parameter is 1 (the default), arts_read/arts_write will block + * when not all data can be read/written successfully, and wait until it + * works. If this parameter is 0, arts_read/arts_write will return + * the number of successfully read/written bytes immediately. + * + * @li ARTS_P_PACKET_SIZE (r) + * This returns the size of the packets used for buffering. The optimal + * size for arts_stream_write is always writing one packet. The buffering of + * streams works with audio packets. So the ARTS_P_BUFFER_SIZE parameter of + * streams (which specifies how many bytes of a stream are prebuffered), + * really consists of (ARTS_P_PACKET_SIZE) * (ARTS_P_PACKET_COUNT). + * + * @li ARTS_P_PACKET_COUNT (r) + * This returns the number of the packets are used for buffering. See + * ARTS_P_PACKET_SIZE for more. + * + * @li ARTS_P_PACKET_SETTINGS (rw) + * This is a way to configure packet size & packet count at the same time. + * The format is 0xCCCCSSSS, where 2^SSSS is the packet size, and CCCC is + * the packet count. Note that when writing this, you don't necessarily + * get the settings you requested. + */ +typedef enum arts_parameter_t_enum arts_parameter_t; + +/** + * initializes the aRts C API, and connects to the sound server + * + * @return 0 if everything is all right, an error code otherwise + */ + +ARTSC_EXPORT int arts_init(void); + +/** + * disconnects from the sound server and frees the aRts C API internals + */ +ARTSC_EXPORT void arts_free(void); + +/** + * asks aRtsd to free the DSP device and return 1 if it was successful, + * 0 if there were active non-suspendable modules + */ +ARTSC_EXPORT int arts_suspend(void); + +/** + * asks aRtsd if the DSP device is free and return 1 if it is, + * 0 if not + */ +ARTSC_EXPORT int arts_suspended(void); + + +/** + * converts an error code to a human readable error message + * + * @param errorcode the errorcode (from another arts function that failed) + * @returns a text string with the error message + */ +ARTSC_EXPORT const char *arts_error_text(int errorcode); + +/** + * open a stream for playing + * + * @param rate the sampling rate (something like 44100) + * @param bits how many bits each sample has (8 or 16) + * @param channels how many channels, 1 is mono, 2 is stereo + * @param name the name of the stream (these will be used so that the user can + * assign streams to effects/mixer channels and similar) + * + * @return a stream + */ +ARTSC_EXPORT arts_stream_t arts_play_stream(int rate, int bits, int channels, const char *name); + +/** + * open a stream for recording + * + * @param rate the sampling rate (something like 44100) + * @param bits how many bits each sample has (8 or 16) + * @param channels how many channels, 1 is mono, 2 is stereo + * @param name the name of the stream (these will be used so that the user can + * assign streams to effects/mixer channels and similar) + * + * @return a stream + */ +ARTSC_EXPORT arts_stream_t arts_record_stream(int rate, int bits, int channels, const char *name); + +/** + * close a stream + */ +ARTSC_EXPORT void arts_close_stream(arts_stream_t stream); + +/** + * read samples from stream + * + * @param stream a previously opened record stream + * @param buffer a buffer with sample data + * @param count the number of bytes contained in the buffer + * + * @returns number of read bytes on success or error code + */ +ARTSC_EXPORT int arts_read(arts_stream_t stream, void *buffer, int count); + +/** + * write samples to to stream + * + * @param stream a previously opened play stream + * @param buffer a buffer with sample data + * @param count the number of bytes contained in the buffer + * + * @returns number of written bytes on success or error code + */ +ARTSC_EXPORT int arts_write(arts_stream_t stream, const void *buffer, int count); + +/** + * configure a parameter of a stream + * + * @param stream an opened record or play stream + * @param parameter the parameter you want to modify + * @param value the new value + * + * @returns the new value of the parameter (which may or may not be the value + * you wanted to have), or an error code if something went wrong + */ +ARTSC_EXPORT int arts_stream_set(arts_stream_t stream, arts_parameter_t param, int value); + +/** + * query a parameter of a stream + * + * @param stream an opened record or play stream + * @param parameter the parameter you want to query + * + * @returns the value of the parameter, or an error code + */ +ARTSC_EXPORT int arts_stream_get(arts_stream_t stream, arts_parameter_t param); + +#ifdef __cplusplus +} +#endif + +#endif /* ARTSC_H */ diff --git a/artsc/artsc_export.h.in b/artsc/artsc_export.h.in new file mode 100644 index 0000000..85fd6ef --- /dev/null +++ b/artsc/artsc_export.h.in @@ -0,0 +1,52 @@ +/* This file is part of the KDE libraries + Copyright (c) 2002-2003 KDE Team + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef ARTSC_EXPORT_H +#define ARTSC_EXPORT_H + +#undef __KDE_HAVE_GCC_VISIBILITY +/** + * The ARTS_NO_EXPORT macro marks the symbol of the given variable + * to be hidden. A hidden symbol is stripped during the linking step, + * so it can't be used from outside the resulting library, which is similar + * to static. However, static limits the visibility to the current + * compilation unit. hidden symbols can still be used in multiple compilation + * units. + * + * \code + * int ARTSC_NO_EXPORT foo; + * int ARTSC_EXPORT bar; + * \end + */ + +#if defined(__KDE_HAVE_GCC_VISIBILITY) +/* Visibility is available for GCC newer than 3.4. + * See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=9283 + */ +#define ARTSC_NO_EXPORT __attribute__ ((visibility("hidden"))) +#define ARTSC_EXPORT __attribute__ ((visibility("default"))) +#elif defined(_WIN32) +#define ARTSC_NO_EXPORT +#define ARTSC_EXPORT __declspec(dllexport) +#else +#define ARTSC_NO_EXPORT +#define ARTSC_EXPORT +#endif + +#endif /* ARTSC_EXPORTS */ diff --git a/artsc/artscbackend.cc b/artsc/artscbackend.cc new file mode 100644 index 0000000..a9f3a91 --- /dev/null +++ b/artsc/artscbackend.cc @@ -0,0 +1,805 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + 2001 Matthias Kretz + kretz@kde.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsc.h" +#include "soundserver.h" +#include "stdsynthmodule.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "arts_export.h" + +#define arts_backend_debug(x) ; + +using namespace std; +using namespace Arts; + +/** + * Base class for streams + */ +class Stream +{ +protected: + SoundServer server; + float serverBufferTime; + + bool _finished, isAttached; + int _samplingRate, _bits, _channels, pos; + string _name; + queue< DataPacket* > streamqueue; + + int packetCount, packetCapacity; + int blockingIO; + + /** + * returns the amount of bytes that will be played in a given amount of + * time in milliseconds + */ + int timeToBytes(float time) + { + float playSpeed = _channels * _samplingRate * _bits / 8; + return (int)(playSpeed * (time / 1000.0)); + } + + /** + * returns the time in milliseconds it takes with the current parameters + * to play a given amount of bytes + */ + float bytesToTime(int size) + { + float playSpeed = _channels * _samplingRate * _bits / 8; + return (1000.0 * ((float)size) / playSpeed); + } + + int bufferSize() { + return packetCount * packetCapacity; + } + + float bufferTime() { + return bytesToTime(bufferSize()); + } + + int bufferSpace() { + int space = 0; + + attach(); + + /* make sure that our information is up-to-date */ + Dispatcher::the()->ioManager()->processOneEvent(false); + + if(!streamqueue.empty()) + { + space += packetCapacity - pos; /* the first, half filled packet */ + + if(streamqueue.size() > 1) /* and the other, empty packets */ + space += (streamqueue.size()-1)*packetCapacity; + } + return space; + } + + int setBufferSize(int size) + { + /* don't change sizes when already streaming */ + if(isAttached) + return ARTS_E_NOIMPL; + + /* + * these parameters are usually a bad idea ;-) however we have to start + * somewhere, and maybe in two years, with a highly optimized kernel + * this is possible - for now, don't request the impossible or don't + * complain if it doesn't work + */ + packetCount = 3; + packetCapacity = 128; + + /* + * - do not configure stream buffers smaller than the server + * recommended value + * - try to get more or less close to the value the application + * wants + */ + int needSize = max(size, timeToBytes(server.minStreamBufferTime())); + + while(bufferSize() < needSize) + { + packetCount++; + if(packetCount == 8) + { + packetCount /= 2; + packetCapacity *= 2; + } + } + + return bufferSize(); + } + + int packetSettings() + { + int settings = 0; + + int cap = packetCapacity; + while(cap > 1) + { + settings++; + cap /= 2; + } + + settings |= packetCount << 16; + return settings; + } + + int setPacketSettings(int settings) + { + /* don't change sizes when already streaming */ + if(isAttached) + return ARTS_E_NOIMPL; + + packetCount = settings >> 16; + + packetCapacity = 1; + int c = settings & 0xffff; + while(c > 0) { + packetCapacity *= 2; + c--; + } + + /* + * - do not configure stream buffers smaller than the server + * recommended value + * - keep the packetSize the applications specified + */ + int needSize = timeToBytes(server.minStreamBufferTime()); + + while(bufferSize() < needSize) + packetCount++; + + return packetSettings(); + } + + /** + * the stream has to attach itself + */ + virtual void attach() = 0; + +public: + Stream(SoundServer server, int rate, int bits, int channels, + string name) : server(server), _finished(false), isAttached(false), + _samplingRate(rate), _bits(bits), _channels(channels), pos(0), + _name(name) + { + serverBufferTime = server.serverBufferTime(); + stream_set(ARTS_P_BUFFER_SIZE,64*1024); + stream_set(ARTS_P_BLOCKING,1); + } + virtual ~Stream() + { + // + } + + virtual int stream_set(arts_parameter_t param, int value) + { + int result; + + switch(param) { + case ARTS_P_BUFFER_SIZE: + return setBufferSize(value); + + case ARTS_P_BUFFER_TIME: + result = setBufferSize(timeToBytes(value)); + if(result < 0) return result; + return (int)bufferTime(); + + case ARTS_P_PACKET_SETTINGS: + return setPacketSettings(value); + + case ARTS_P_BLOCKING: + if(value != 0 && value != 1) return ARTS_E_NOIMPL; + + blockingIO = value; + return blockingIO; + /* + * maybe ARTS_P_TOTAL_LATENCY _could_ be made writeable, the + * others are of course useless + */ + case ARTS_P_BUFFER_SPACE: + case ARTS_P_SERVER_LATENCY: + case ARTS_P_TOTAL_LATENCY: + case ARTS_P_PACKET_SIZE: + case ARTS_P_PACKET_COUNT: + return ARTS_E_NOIMPL; + } + return ARTS_E_NOIMPL; + } + + virtual int stream_get(arts_parameter_t param) + { + switch(param) { + case ARTS_P_BUFFER_SIZE: + return bufferSize(); + + case ARTS_P_BUFFER_TIME: + return (int)bufferTime(); + + case ARTS_P_BUFFER_SPACE: + return bufferSpace(); + + case ARTS_P_PACKET_SETTINGS: + return packetSettings(); + + case ARTS_P_SERVER_LATENCY: + return (int)serverBufferTime; + + case ARTS_P_TOTAL_LATENCY: + return stream_get(ARTS_P_SERVER_LATENCY) + + stream_get(ARTS_P_BUFFER_TIME); + + case ARTS_P_BLOCKING: + return blockingIO; + + case ARTS_P_PACKET_SIZE: + return packetCapacity; + + case ARTS_P_PACKET_COUNT: + return packetCount; + } + return ARTS_E_NOIMPL; + } + + virtual int write(const mcopbyte * /*data*/, int /*size*/) + { + return ARTS_E_NOIMPL; + } + + virtual int read(mcopbyte * /*data*/, int /*size*/) + { + return ARTS_E_NOIMPL; + } + + virtual void close() = 0; + + int suspend() + { + if(isAttached) + { + return server.suspend(); + } + return 0; + } + + int suspended() + { + if(isAttached) + { + return 0; + } + return server.suspended(); + } +}; + +class Receiver : public ByteSoundReceiver_skel, + public StdSynthModule, + virtual public Stream +{ + /* + * FIXME: bsWrapper is a more or less ugly trick to be able to use + * this object although not using smartwrappers to access it + */ + ByteSoundReceiver bsWrapper; + +protected: + virtual void attach() + { + if(!isAttached) + { + isAttached = true; + + server.attachRecorder(bsWrapper); + start(); + + /* + * TODO: this processOneEvent looks a bit strange here... it is + * there since StdIOManager does block 5 seconds on the first + * arts_write if it isn't - although notifications are pending + * + * Probably the real solution is to rewrite the + * StdIOManager::processOneEvent function. (And maybe drop the + * assumption that aRts will not block when an infinite amount + * of notifications is pending - I mean: will it ever happen?) + */ + Dispatcher::the()->ioManager()->processOneEvent(false); + } + } + +public: + Receiver(SoundServer server, int rate, int bits, int channels, + string name) : Stream( server, rate, bits, channels, name) + { + bsWrapper = ByteSoundReceiver::_from_base(this); + } + + virtual ~Receiver() { + // + } + + long samplingRate() { return _samplingRate; } + long channels() { return _channels; } + long bits() { return _bits; } + bool finished() { return _finished; } + string title() { return _name; } + + void process_indata(DataPacket *packet) + { + streamqueue.push(packet); + } + + void close() + { + if(isAttached) + { + /* remove all packets from the streamqueue */ + while(!streamqueue.empty()) + { + DataPacket *packet = streamqueue.front(); + packet->processed(); + streamqueue.pop(); + } + + server.detachRecorder(bsWrapper); + } + // similar effect like "delete this;" + bsWrapper = ByteSoundReceiver::null(); + } + + int read(mcopbyte *data, int size) + { + attach(); + + int remaining = size; + while(remaining) + { + if(blockingIO) + { + /* C API blocking style read */ + while(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(true); + } + else + { + /* non blocking I/O */ + if(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(false); + + /* still no more packets to read? */ + if(streamqueue.empty()) + return size - remaining; + } + + /* get a packet */ + DataPacket *packet = streamqueue.front(); + + /* copy some data from there */ + int tocopy = min(remaining,packet->size-pos); + memcpy(data,&packet->contents[pos],tocopy); + pos += tocopy; + data += tocopy; + remaining -= tocopy; + + /* have we read the whole packet? then get rid of it */ + if(pos == packet->size) + { + packet->processed(); + streamqueue.pop(); + pos = 0; + } + } + + /* no possible error conditions */ + return size; + } +}; + +class Sender : public ByteSoundProducerV2_skel, + public StdSynthModule, + virtual public Stream +{ + /* + * FIXME: bsWrapper is a more or less ugly trick to be able to use + * this object although not using smartwrappers to access it + */ + ByteSoundProducerV2 bsWrapper; + +protected: + virtual void attach() + { + if(!isAttached) + { + isAttached = true; + + server.attach(bsWrapper); + start(); + + /* + * TODO: this processOneEvent looks a bit strange here... it is + * there since StdIOManager does block 5 seconds on the first + * arts_write if it isn't - although notifications are pending + * + * Probably the real solution is to rewrite the + * StdIOManager::processOneEvent function. (And maybe drop the + * assumption that aRts will not block when an infinite amount + * of notifications is pending - I mean: will it ever happen?) + */ + Dispatcher::the()->ioManager()->processOneEvent(false); + } + } + +public: + Sender(SoundServer server, int rate, int bits, int channels, + string name) : Stream( server, rate, bits, channels, name) + { + bsWrapper = ByteSoundProducerV2::_from_base(this); + } + + virtual ~Sender() { + // + } + + long samplingRate() { return _samplingRate; } + long channels() { return _channels; } + long bits() { return _bits; } + bool finished() { return _finished; } + string title() { return _name; } + + void streamStart() + { + /* + * start streaming + */ + outdata.setPull(packetCount, packetCapacity); + } + + void request_outdata(DataPacket *packet) + { + streamqueue.push(packet); + } + + void close() + { + if(isAttached) + { + if(pos != 0) + { + /* send the last half-filled packet */ + DataPacket *packet = streamqueue.front(); + packet->size = pos; + packet->send(); + streamqueue.pop(); + } + outdata.endPull(); + + /* remove all packets from the streamqueue */ + while(!streamqueue.empty()) + { + DataPacket *packet = streamqueue.front(); + packet->size = 0; + packet->send(); + streamqueue.pop(); + } + + server.detach(bsWrapper); + } + // similar effect like "delete this;" + Arts::ByteSoundProducerV2_base* x = _copy(); + bsWrapper = ByteSoundProducerV2::null(); + x->_release(); + } + + int write(const mcopbyte *data, int size) + { + attach(); + + int remaining = size; + while(remaining) + { + if(blockingIO) + { + /* C API blocking style write */ + /* we're not waiting for any data here, but rather for + * DataPackets that we can fill */ + while(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(true); + } + else + { + /* non blocking I/O */ + if(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(false); + + /* still no more space to write? */ + if(streamqueue.empty()) + return size - remaining; + } + + /* get a packet */ + DataPacket *packet = streamqueue.front(); + + /* copy some data there */ + int tocopy = min(remaining,packetCapacity-pos); + memcpy(&packet->contents[pos],data,tocopy); + pos += tocopy; + data += tocopy; + remaining -= tocopy; + + /* have we filled up the packet? then send it */ + if(pos == packetCapacity) + { + packet->size = packetCapacity; + packet->send(); + streamqueue.pop(); + pos = 0; + } + } + + /* no possible error conditions */ + return size; + } +}; + +class ArtsCApi { +protected: + static ArtsCApi *instance; + int refcnt; + + Dispatcher dispatcher; + SoundServer server; + + ArtsCApi() : refcnt(1), server(Reference("global:Arts_SoundServer")) + { + // + } + +public: +// C Api commands + int init() { + if(server.isNull()) + return ARTS_E_NOSERVER; + + return 0; + } + + int suspend() { + if(!server.isNull()) + return server.suspend()? 1:0; + return ARTS_E_NOSERVER; + } + + int suspended() { + if(!server.isNull()) + return server.suspended()? 1:0; + return ARTS_E_NOSERVER; + } + + void free() { + // nothing to do + } + + arts_stream_t play_stream(int rate, int bits, int channels, const char *name) + { + if(server.isNull()) + return 0; + + return (arts_stream_t)static_cast(new Sender(server,rate,bits,channels,name)); + } + + arts_stream_t record_stream(int rate, int bits, int channels, const char *name) + { + if(server.isNull()) + return 0; + + return (arts_stream_t)static_cast(new Receiver(server,rate,bits,channels,name)); + } + + void close_stream(arts_stream_t stream) + { + if(server.isNull()) + return; + + if(!stream) + return; + + static_cast(stream)->close(); + } + + int write(arts_stream_t stream, const void *data, int size) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->write((const mcopbyte *)data,size); + } + + int read(arts_stream_t stream, void *data, int size) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->read((mcopbyte *)data,size); + } + + int stream_set(arts_stream_t stream, arts_parameter_t param, int value) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->stream_set(param,value); + } + + int stream_get(arts_stream_t stream, arts_parameter_t param) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->stream_get(param); + } + +// allocation and freeing of the class + static ArtsCApi *the() { + return instance; + } + static void ref() { + if(!instance) + instance = new ArtsCApi(); + else + instance->refcnt++; + } + static void release() { + assert(instance); + assert(instance->refcnt > 0); + instance->refcnt--; + if(instance->refcnt == 0) + { + delete instance; + instance = 0; + } + } +}; + +//----------------------------- static members ------------------------------- + +ArtsCApi *ArtsCApi::instance = 0; + +//------------------ wrappers from C to C++ class ---------------------------- + +extern "C" ARTSC_EXPORT int arts_backend_init() +{ + arts_backend_debug("arts_backend_init"); + ArtsCApi::ref(); + + // if init fails, don't expect free, and don't expect that the user + // continues using other API functions + int rc = ArtsCApi::the()->init(); + if(rc < 0) ArtsCApi::release(); + return rc; +} + +extern "C" ARTSC_EXPORT int arts_backend_suspend() +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + arts_backend_debug("arts_backend_suspend"); + return ArtsCApi::the()->suspend(); +} + +extern "C" ARTSC_EXPORT int arts_backend_suspended() +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + arts_backend_debug("arts_backend_suspended"); + return ArtsCApi::the()->suspended(); +} + +extern "C" ARTSC_EXPORT void arts_backend_free() +{ + if(!ArtsCApi::the()) return; + + arts_backend_debug("arts_backend_free"); + ArtsCApi::the()->free(); + ArtsCApi::release(); +} + +extern "C" ARTSC_EXPORT arts_stream_t arts_backend_play_stream(int rate, int bits, int channels, const char *name) +{ + if(!ArtsCApi::the()) return 0; + + arts_backend_debug("arts_backend_play_stream"); + return ArtsCApi::the()->play_stream(rate,bits,channels,name); +} + +extern "C" ARTSC_EXPORT arts_stream_t arts_backend_record_stream(int rate, int bits, int channels, const char *name) +{ + if(!ArtsCApi::the()) return 0; + + arts_backend_debug("arts_backend_record_stream"); + return ArtsCApi::the()->record_stream(rate,bits,channels,name); +} + +extern "C" ARTSC_EXPORT void arts_backend_close_stream(arts_stream_t stream) +{ + if(!ArtsCApi::the()) return; + + arts_backend_debug("arts_backend_close_stream"); + ArtsCApi::the()->close_stream(stream); +} + +extern "C" ARTSC_EXPORT int arts_backend_read(arts_stream_t stream, void *buffer, int count) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_backend_read"); + return ArtsCApi::the()->read(stream,buffer,count); +} + +extern "C" ARTSC_EXPORT int arts_backend_write(arts_stream_t stream, const void *buffer, + int count) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_backend_write"); + return ArtsCApi::the()->write(stream,buffer,count); +} + +extern "C" ARTSC_EXPORT int arts_backend_stream_set(arts_stream_t stream, + arts_parameter_t param, int value) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_stream_set"); + return ArtsCApi::the()->stream_set(stream,param,value); +} + +extern "C" ARTSC_EXPORT int arts_backend_stream_get(arts_stream_t stream, + arts_parameter_t param) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_stream_get"); + return ArtsCApi::the()->stream_get(stream,param); +} diff --git a/artsc/artsdsp.c b/artsc/artsdsp.c new file mode 100644 index 0000000..368b15f --- /dev/null +++ b/artsc/artsdsp.c @@ -0,0 +1,675 @@ +/* Evil evil evil hack to get OSS apps to cooperate with artsd + * This is based on the original esddsp, which esd uses to do the same. + * + * Copyright (C) 1998 Manish Singh + * Copyright (C) 2000 Stefan Westerfeld (aRts port) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#define _GNU_SOURCE 1 + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_SOUNDCARD_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* #include */ +#include + +#include +#include + +#include "arts_export.h" +/* + * NOTE: + * + * To truly support non-blocking I/O, there is some stuff missing. Namely, + * select should be trapped and redirected, as well as the means for making + * a stream non-blocking and so on. Maybe poll, too. + * + * Currently, only apps that are doing blocking I/O will probably work right. + */ + +/** + * the stream status: sndfd is -1 when unused, otherwise it is a useless fd + * which points to /dev/null, to ensure compatibility with more weird + * operations on streams + * + * settings contains what has already been set (speed, bits, channels), and + * is 7 when all of these are true + * + * stream contains an aRts stream or 0 + */ +static int sndfd = -1; +static int settings; +static int arts_init_done = 0; +static arts_stream_t stream = 0; +static arts_stream_t record_stream = 0; +static int bits = 0; +static int speed = 0; +static int channels = 0; +static int frags; + +#if defined(HAVE_IOCTL_INT_INT_DOTS) +typedef int ioctl_request_t; +#elif defined(HAVE_IOCTL_INT_ULONG_DOTS) +typedef unsigned long ioctl_request_t; +#elif defined(HAVE_IOCTL_INT_ULONGINT_DOTS) +typedef unsigned long int ioctl_request_t; +#else +#error "unknown ioctl type (check config.h, adapt configure test)..." +#endif + +/* + * memory mapping emulation + */ +static int mmapemu = 0; +static count_info mmapemu_ocount; +static char *mmapemu_obuffer = 0; +static int mmapemu_osize = 0; + +/* + * original C library functions + */ +typedef int (*orig_open_ptr)(const char *pathname, int flags, ...); +typedef int (*orig_close_ptr)(int fd); +typedef int (*orig_ioctl_ptr)(int fd, ioctl_request_t request, ...); +typedef ssize_t (*orig_write_ptr)(int fd, const void *buf, size_t count); +typedef ssize_t (*orig_read_ptr)(int fd, void *buf, size_t count); +typedef void* (*orig_mmap_ptr)(void *start, size_t length, int prot, + int flags, int fd, off_t offset); +typedef int (*orig_munmap_ptr)(void *start, size_t length); +typedef FILE* (*orig_fopen_ptr)(const char *path, const char *mode); +typedef int (*orig_access_ptr)(const char *pathname, int mode); + +static orig_open_ptr orig_open; +static orig_close_ptr orig_close; +static orig_ioctl_ptr orig_ioctl; +static orig_write_ptr orig_write; +static orig_read_ptr orig_read; +static orig_mmap_ptr orig_mmap; +static orig_munmap_ptr orig_munmap; +static orig_fopen_ptr orig_fopen; +static orig_access_ptr orig_access; + +static int artsdsp_debug = 0; +static int artsdsp_init = 0; + +void *mmap(void *start, size_t length, int prot, int flags, + int fd, off_t offset); +int munmap(void *start, size_t length); +#define CHECK_INIT() if(!artsdsp_init) artsdsp_doinit(); + +/* + * Initialization - maybe this should be either be a startup only called + * routine, or use pthread locks to prevent strange effects in multithreaded + * use (however it seems highly unlikely that an application would create + * multiple threads before even using one of redirected the system functions + * once). + */ + +static void artsdsp_doinit() +{ + const char *env; + artsdsp_init = 1; + + /* debugging? */ + env = getenv("ARTSDSP_VERBOSE"); + artsdsp_debug = env && !strcmp(env,"1"); + + /* mmap emulation? */ + env = getenv("ARTSDSP_MMAP"); + mmapemu = env && !strcmp(env,"1"); + + /* resolve original symbols */ + orig_open = (orig_open_ptr)dlsym(RTLD_NEXT,"open"); + orig_close = (orig_close_ptr)dlsym(RTLD_NEXT,"close"); + orig_write = (orig_write_ptr)dlsym(RTLD_NEXT,"write"); + orig_read = (orig_read_ptr)dlsym(RTLD_NEXT,"read"); + orig_ioctl = (orig_ioctl_ptr)dlsym(RTLD_NEXT,"ioctl"); + orig_mmap = (orig_mmap_ptr)dlsym(RTLD_NEXT,"mmap"); + orig_munmap = (orig_munmap_ptr)dlsym(RTLD_NEXT,"munmap"); + orig_fopen = (orig_fopen_ptr)dlsym(RTLD_NEXT,"fopen"); + orig_access = (orig_access_ptr)dlsym(RTLD_NEXT,"access"); +} + +static void +#ifdef __GNUC__ + __attribute__( ( format ( printf, 1, 2 ) ) ) +#endif +artsdspdebug(const char *fmt,...) +{ + CHECK_INIT(); + + if(artsdsp_debug) + { + va_list ap; + va_start(ap, fmt); + (void) vfprintf(stderr, fmt, ap); + va_end(ap); + } +} + +static void mmapemu_flush() +{ + int space; + + if (mmapemu_osize == 0) { + return; + } + + space = arts_stream_get(stream, ARTS_P_BUFFER_SPACE); + artsdspdebug("space = %d\n",space); + while(space >= 4096) + { + arts_write(stream,&mmapemu_obuffer[mmapemu_ocount.ptr],4096); + space -= 4096; + mmapemu_ocount.ptr += 4096; + mmapemu_ocount.ptr %= mmapemu_osize; + mmapemu_ocount.blocks++; + mmapemu_ocount.bytes += 4096; + } +} + +/* returns 1 if the filename points to a sound device */ +static int is_sound_device(const char *pathname) +{ + if(!pathname) return 0; + if(strcmp(pathname,"/dev/dsp") == 0) return 1; + if(strcmp(pathname,"/dev/sound/dsp") == 0) return 1; + return 0; +} + +int open (const char *pathname, int flags, ...) +{ + va_list args; + mode_t mode = 0; + + CHECK_INIT(); + + /* + * After the documentation, va_arg is not safe if there is no argument to + * get "random errors will occur", so only get it in case O_CREAT is set, + * and hope that passing 0 to the orig_open function in all other cases + * will work. + */ + va_start(args,flags); + if(flags & O_CREAT) { + /* The compiler will select one of these at compile-tyime if -O is used. + * Otherwise, it may be deferred until runtime. + */ + if (sizeof(int) >= sizeof(mode_t)) { + mode = va_arg(args, int); + } else { + mode = va_arg(args, mode_t); + } + } + va_end(args); + + if (!is_sound_device(pathname)) /* original open for anything but sound */ + return orig_open (pathname, flags, mode); + + settings = 0; + frags = 0; + stream = 0; + record_stream = 0; + + artsdspdebug ("aRts: hijacking /dev/dsp open...\n"); + + sndfd = orig_open("/dev/null",flags,mode); + if(sndfd >= 0) + { + if(!arts_init_done) { + int rc = arts_init(); + if(rc < 0) { + artsdspdebug("error on aRts init: %s\n", arts_error_text(rc)); + orig_close(sndfd); + sndfd = -1; + return orig_open (pathname, flags, mode); + } + else arts_init_done = 1; + } + } + + /* success */ + return sndfd; +} + +int ioctl (int fd, ioctl_request_t request, ...) +{ + int space, size, latency, odelay; + + /* + * FreeBSD needs ioctl with varargs. However I have no idea how to "forward" + * the variable args ioctl to the orig_ioctl routine. So I expect the ioctl + * to have exactly one pointer-like parameter and forward that, hoping that + * it works + */ + va_list args; + void *argp; + va_start(args,request); + argp = va_arg(args, void *); + va_end(args); + + CHECK_INIT(); + + if (fd != sndfd ) + return orig_ioctl (fd, request, argp); + else if (sndfd != -1) + { + int *arg = (int *) argp; + artsdspdebug("aRts: hijacking /dev/dsp ioctl (%d : %x - %p)\n", + ( int ) fd, ( int ) request, ( void* ) argp); + + switch (request) + { + struct audio_buf_info *audiop; +#ifdef SNDCTL_DSP_RESET + case SNDCTL_DSP_RESET: /* _SIO ('P', 0) */ + artsdspdebug("aRts: SNDCTL_DSP_RESET unsupported\n"); + break; +#endif + +#ifdef SNDCTL_DSP_SYNC + case SNDCTL_DSP_SYNC: /* _SIO ('P', 1) */ + artsdspdebug("aRts: SNDCTL_DSP_SYNC unsupported\n"); + break; +#endif + +#ifdef SNDCTL_DSP_SPEED + case SNDCTL_DSP_SPEED: /* _SIOWR('P', 2, int) */ + speed = *arg; + settings |= 2; + break; +#endif + +#ifdef SNDCTL_DSP_STEREO + case SNDCTL_DSP_STEREO: /* _SIOWR('P', 3, int) */ + channels = (*arg)?2:1; + settings |= 4; + break; +#endif + +#ifdef SNDCTL_DSP_GETBLKSIZE + case SNDCTL_DSP_GETBLKSIZE: /* _SIOWR('P', 4, int) */ + if(mmapemu) + *arg = 4096; + else if(stream) + *arg = arts_stream_get(stream,ARTS_P_PACKET_SIZE); + else + { + int fragSize = frags & 0x7fff; + if(fragSize > 1 && fragSize < 16) + *arg = (1 << fragSize); + else + *arg = 16384; /* no idea ;-) */ + } + break; +#endif + +#ifdef SNDCTL_DSP_SETFMT + case SNDCTL_DSP_SETFMT: /* _SIOWR('P',5, int) */ + bits = (*arg & 0x30) ? 16 : 8; + settings |= 1; + break; +#endif + +#ifdef SNDCTL_DSP_CHANNELS + case SNDCTL_DSP_CHANNELS: /* _SIOWR('P', 6, int) */ + channels = (*arg); + settings |= 4; + break; +#endif + +#ifdef SOUND_PCM_WRITE_FILTER + case SOUND_PCM_WRITE_FILTER: /* _SIOWR('P', 7, int) */ + artsdspdebug("aRts: SNDCTL_DSP_WRITE_FILTER(%d) unsupported\n",*arg); + break; +#endif + +#ifdef SNDCTL_DSP_POST + case SNDCTL_DSP_POST: /* _SIO ('P', 8) */ + artsdspdebug("aRts: SNDCTL_DSP_POST unsupported\n"); + break; +#endif + +#ifdef SNDCTL_DSP_SUBDIVIDE + case SNDCTL_DSP_SUBDIVIDE: /* _SIOWR('P', 9, int) */ + artsdspdebug("aRts: SNDCTL_DSP_SUBDIVIDE(%d) unsupported\n",*arg); + break; +#endif + +#ifdef SNDCTL_DSP_SETFRAGMENT + case SNDCTL_DSP_SETFRAGMENT: /* _SIOWR('P',10, int) */ + artsdspdebug("aRts: SNDCTL_DSP_SETFRAGMENT(%x) partially supported\n", + *arg); + frags = *arg; + break; +#endif + +#ifdef SNDCTL_DSP_GETFMTS + case SNDCTL_DSP_GETFMTS: /* _SIOR ('P',11, int) */ + *arg = 8 | 16; + break; +#endif + +#if defined(SNDCTL_DSP_GETOSPACE) && defined(SNDCTL_DSP_GETISPACE) + case SNDCTL_DSP_GETOSPACE: /* _SIOR ('P',12, audio_buf_info) */ + case SNDCTL_DSP_GETISPACE: /* _SIOR ('P',13, audio_buf_info) */ + audiop = argp; + if(mmapemu) + { + audiop->fragstotal = 16; + audiop->fragsize = 4096; + audiop->bytes = 0; /* FIXME: is this right? */ + audiop->fragments = 0; + } + else + { + audiop->fragstotal = + stream?arts_stream_get(stream, ARTS_P_PACKET_COUNT):10; + audiop->fragsize = + stream?arts_stream_get(stream, ARTS_P_PACKET_SIZE):16384; + audiop->bytes = + stream?arts_stream_get(stream, ARTS_P_BUFFER_SPACE):16384; + audiop->fragments = audiop->bytes / audiop->fragsize; + } + break; +#endif + +#ifdef SNDCTL_DSP_NONBLOCK + case SNDCTL_DSP_NONBLOCK: /* _SIO ('P',14) */ + artsdspdebug("aRts: SNDCTL_DSP_NONBLOCK unsupported\n"); + break; +#endif + +#ifdef SNDCTL_DSP_GETCAPS + case SNDCTL_DSP_GETCAPS: /* _SIOR ('P',15, int) */ + if(mmapemu) + *arg = DSP_CAP_MMAP | DSP_CAP_TRIGGER | DSP_CAP_REALTIME | DSP_CAP_DUPLEX; + else + *arg = DSP_CAP_DUPLEX; + break; +#endif + +#ifdef SNDCTL_DSP_GETTRIGGER + case SNDCTL_DSP_GETTRIGGER: /* _SIOR ('P',16, int) */ + artsdspdebug("aRts: SNDCTL_DSP_GETTRIGGER unsupported\n"); + break; +#endif + +#ifdef SNDCTL_DSP_SETTRIGGER + case SNDCTL_DSP_SETTRIGGER: /* _SIOW ('P',16, int) */ + artsdspdebug("aRts: SNDCTL_DSP_SETTRIGGER unsupported\n"); + break; +#endif + +#ifdef SNDCTL_DSP_GETIPTR + case SNDCTL_DSP_GETIPTR: /* _SIOR ('P',17, count_info) */ + artsdspdebug("aRts: SNDCTL_DSP_GETIPTR unsupported\n"); + break; +#endif + +#ifdef SNDCTL_DSP_GETOPTR + case SNDCTL_DSP_GETOPTR: /* _SIOR ('P',18, count_info) */ + if(mmapemu) + { + mmapemu_flush(); + *((count_info *)arg) = mmapemu_ocount; + mmapemu_ocount.blocks = 0; + } + else + { + artsdspdebug("aRts: SNDCTL_DSP_GETOPTR unsupported\n"); + } + break; +#endif + +#ifdef SNDCTL_DSP_MAPINBUF + case SNDCTL_DSP_MAPINBUF: /* _SIOR ('P', 19, buffmem_desc) */ + artsdspdebug("aRts: SNDCTL_DSP_MAPINBUF unsupported\n"); + break; +#endif + +#ifdef SNDCTL_DSP_MAPOUTBUF + case SNDCTL_DSP_MAPOUTBUF: /* _SIOR ('P', 20, buffmem_desc) */ + artsdspdebug("aRts: SNDCTL_DSP_MAPOUTBUF unsupported\n"); + break; +#endif + +#ifdef SNDCTL_DSP_SETSYNCRO + case SNDCTL_DSP_SETSYNCRO: /* _SIO ('P', 21) */ + artsdspdebug("aRts: SNDCTL_DSP_SETSYNCHRO unsupported\n"); + break; +#endif + +#ifdef SNDCTL_DSP_SETDUPLEX + case SNDCTL_DSP_SETDUPLEX: /* _SIO ('P', 22) */ + artsdspdebug("aRts: SNDCTL_DSP_SETDUPLEX unsupported\n"); + break; +#endif + +#ifdef SNDCTL_DSP_GETODELAY + case SNDCTL_DSP_GETODELAY: /* _SIOR ('P', 23, int) */ + space = arts_stream_get(stream, ARTS_P_BUFFER_SPACE); + size = arts_stream_get(stream, ARTS_P_BUFFER_SIZE); + latency = arts_stream_get(stream, ARTS_P_SERVER_LATENCY); + odelay = size - space + (latency * speed * bits * channels) / 8000; + artsdspdebug("aRts: SNDCTL_DSP_GETODELAY returning %d\n", odelay); + *arg = odelay; + break; +#endif + + default: + artsdspdebug("aRts: unhandled /dev/dsp ioctl (%lx - %p)\n",request, argp); + break; + } + + if (settings == 7 && !stream) + { + const char *name = getenv("ARTSDSP_NAME"); + int fragSize = (frags & 0x7fff); + int fragCount = (frags & 0x7fff0000) >> 16; + + artsdspdebug ("aRts: creating stream...\n"); + stream = arts_play_stream(speed,bits,channels,name?name:"artsdsp"); + + if(fragSize > 1 && fragSize < 16) + { + /* + * if fragment settings are way too large (unrealistic), we + * will assume that the user didn't mean it, and let the C API + * choose a convenient number >= 3 + */ + if(fragCount < 2 || fragCount > 8192 + || (fragCount * (1 << fragSize)) > 128*1024) + { + frags = 0x00030000+fragSize; + } + + arts_stream_set(stream,ARTS_P_PACKET_SETTINGS,frags); + } + if(mmapemu) + { + arts_stream_set(stream,ARTS_P_PACKET_SETTINGS,0x0002000c); + mmapemu_ocount.ptr=mmapemu_ocount.blocks=mmapemu_ocount.bytes=0; + artsdspdebug("aRts: total latency = %dms, buffer latency = %dms\n", + arts_stream_get(stream,ARTS_P_TOTAL_LATENCY), + arts_stream_get(stream, ARTS_P_BUFFER_TIME)); + } + } + + return 0; + } + + return 0; +} + +int close(int fd) +{ + CHECK_INIT(); + + if (fd != sndfd) + return orig_close (fd); + else if (sndfd != -1) + { + artsdspdebug ("aRts: /dev/dsp close...\n"); + if(stream) + { + arts_close_stream(stream); + stream = 0; + } + if (record_stream) + { + arts_close_stream(record_stream); + record_stream = 0; + } + if(mmapemu && mmapemu_obuffer) + { + free(mmapemu_obuffer); + mmapemu_obuffer = 0; + } + + /* + * there are problems with library unloading in conjunction with X11, + * (Arts::X11GlobalComm), so we don't unload stuff again here + */ + + /* arts_free(); */ + + orig_close(sndfd); + sndfd = -1; + } + return 0; +} + +int access(const char *pathname, int mode) +{ + CHECK_INIT(); + + if (!is_sound_device(pathname)) /* original open for anything but sound */ + return orig_access (pathname, mode); + else + artsdspdebug ("aRts: /dev/dsp access...\n"); + return 0; +} + +ssize_t write (int fd, const void *buf, size_t count) +{ + CHECK_INIT(); + + if(fd != sndfd) + return orig_write(fd,buf,count); + else if(sndfd != -1) + { + artsdspdebug ("aRts: /dev/dsp write...\n"); + if(stream != 0) + { + return arts_write(stream,buf,count); + } + } + return 0; +} + +ssize_t read (int fd, void *buf, size_t count) +{ + CHECK_INIT(); + + if (fd != sndfd) + return orig_read(fd,buf,count); + else if (sndfd == -1) + return 0; + + if (!record_stream) + record_stream = arts_record_stream(speed, bits, channels, "artsdsp"); + artsdspdebug ( "aRts: /dev/dsp read...\n" ); + return arts_read(record_stream, buf, count); +} + +void *mmap(void *start, size_t length, int prot, int flags, + int fd, off_t offset) +{ + CHECK_INIT(); + + if(fd != sndfd || sndfd == -1) + return orig_mmap(start,length,prot,flags,fd,offset); + else + { + artsdspdebug ("aRts: mmap - start = %p, length = %zd, prot = %d\n", + start, length, prot); + artsdspdebug (" flags = %d, fd = %d, offset = %ld\n",flags, fd,offset); + + if(mmapemu && length > 0) + { + mmapemu_osize = length; + mmapemu_obuffer = malloc(length); + mmapemu_ocount.ptr = mmapemu_ocount.blocks = mmapemu_ocount.bytes = 0; + return mmapemu_obuffer; + } + else artsdspdebug ("aRts: /dev/dsp mmap (unsupported, try -m option)...\n"); + } + return (void *)-1; +} + +int munmap(void *start, size_t length) +{ + CHECK_INIT(); + + if(start != mmapemu_obuffer || mmapemu_obuffer == 0) + return orig_munmap(start,length); + + artsdspdebug ("aRts: /dev/dsp munmap...\n"); + mmapemu_obuffer = 0; + free(start); + + return 0; +} + +#ifdef HAVE_ARTSDSP_STDIO_EMU + +/* + * use #include rather than linking, because we want to keep everything + * static inside artsdsp to be sure that we don't override application symbols + */ +#include "stdioemu.c" + +FILE* fopen(const char *path, const char *mode) +{ + CHECK_INIT(); + + if (!is_sound_device(path)) /* original open for anything but sound */ + return orig_fopen (path, mode); + + artsdspdebug ("aRts: hijacking /dev/dsp fopen...\n"); + + return fake_fopen(path, mode); +} +#endif + +#endif +/* + * vim:ts=4 + */ diff --git a/artsc/artsdsp.in b/artsc/artsdsp.in new file mode 100755 index 0000000..084a716 --- /dev/null +++ b/artsc/artsdsp.in @@ -0,0 +1,106 @@ +#!/bin/sh +# artsdsp - wrapper script to allow *some* binary only programs to use artsd +# based on the esddsp script + +# keep this in sync with artsversion.h +version="@ARTS_VERSION@" + +# default values for script variables +verbose=0 +set_name=0 +single_thread=0 + +# check for artsdsp options +while test $# -gt 0; do + + case "$1" in + + -h|--help) + echo "artsdsp - attempt to reroute audio device to artsd" + echo " " + echo "artsdsp [options] application arguments" + echo " " + echo "options:" + echo "-h, --help show brief help" + echo "-n, --name=NAME use name to identify player to artsd" + echo "-m, --mmap emulate memory mapping (i.e. for quake)" + echo "-s, --single-threaded use the single-threaded version" + echo "-v, --verbose show parameters" + echo "-V, --version show version" + exit 0 + ;; + + -n) + shift + if test $# -gt 0; then + export ARTSDSP_NAME=$1 + else + echo "no player name specified" + exit 1 + fi + shift + set_name=1 + ;; + + --name*) + export ARTSDSP_NAME=`echo $1 | sed -e 's/^[^=]*=//g'` + set_name=1 + shift + ;; + + -v|--verbose) + verbose=1 + shift + ;; + + -V|--version) + echo "artsdsp $version" + exit + ;; + + -m|--mmap) + export ARTSDSP_MMAP=1 + shift + ;; + + -s|--single-threaded) + single_thread=1 + shift + ;; + + *) + # no more artsdsp options, get on with life + break + ;; + esac +done + +# echo options if verbose specified +if test "$verbose" = 1; then + ARTSDSP_VERBOSE=1 + export ARTSDSP_VERBOSE + echo "artsdsp: $version" + echo "name: $ARTSDSP_NAME" + echo "command line: $@" + if test "$single_thread" = 1; then + echo "threaded: no" + else + echo "threaded: yes" + fi +fi + +prefix=@prefix@ +exec_prefix=@exec_prefix@ + +if test "$single_thread" = 1; then + LD_PRELOAD=${exec_prefix}/\$LIB/libartsdsp_st.so.0 +else + LD_PRELOAD=${exec_prefix}/\$LIB/libartsdsp.so.0:${exec_prefix}/\$LIB/libartsc.so.0 +fi +if test -f ${exec_prefix}/\$LIB/libdl.so.2; then + LD_PRELOAD=$LD_PRELOAD:${exec_prefix}/\$LIB/libdl.so.2 +fi +export LD_PRELOAD + +# invoke the program with the args given +exec "$@" diff --git a/artsc/stdioemu.c b/artsc/stdioemu.c new file mode 100644 index 0000000..2b3bc1c --- /dev/null +++ b/artsc/stdioemu.c @@ -0,0 +1,96 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +/* + * This source only exists because some very special programs think that + * it is a very special idea to access /dev/dsp by the means of stdio, so + * we need to fake FILE* access for artsdsp as well. + * + * To do so, it relies on glibc internals, so that it will probably not work + * on other systems - but then again, it might not be necessary on other + * systems, when fopen properly calls open, it might as well work unchanged. + */ + + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include + +struct fd_cookie { + int fd; +}; + +static ssize_t fdc_read (void *cookie, char *buffer, size_t size) +{ + struct fd_cookie *fdc = (struct fd_cookie *)cookie; + return read(fdc->fd, buffer, size); +} + +static ssize_t fdc_write (void *cookie, const char *buffer, size_t size) +{ + struct fd_cookie *fdc = (struct fd_cookie *)cookie; + return write(fdc->fd, buffer, size); +} + +static int fdc_seek (void* cookie, off64_t* position, int whence) +{ + return -1; +} + +static int fdc_clean (void *cookie) +{ + struct fd_cookie *fdc = (struct fd_cookie *)cookie; + int result = close(fdc->fd); + free(cookie); + return result; +} + +static FILE *fake_fopen(const char *path, const char *mode) +{ + cookie_io_functions_t fns = { fdc_read, fdc_write, fdc_seek, fdc_clean }; + struct fd_cookie *fdc = + (struct fd_cookie *)malloc(sizeof(struct fd_cookie)); + const char *mptr; + int open_mode = 0; + FILE *result = 0; + + for(mptr = mode; *mptr; mptr++) + { + if(*mptr == 'r') open_mode |= 1; /* 1 = read */ + if(*mptr == 'w') open_mode |= 2; /* 2 = write */ + if(*mptr == '+') open_mode |= 3; /* 3 = readwrite */ + if(*mptr == 'a') open_mode |= 2; /* append -> write */ + } + if(open_mode == 1) fdc->fd = open(path,O_RDONLY,0666); + if(open_mode == 2) fdc->fd = open(path,O_WRONLY,0666); + if(open_mode == 3) fdc->fd = open(path,O_RDWR,0666); + + if(open_mode && fdc->fd > 0) + { + result = fopencookie (fdc,"w", fns); + result->_fileno = fdc->fd; /* ugly patchy slimy kludgy hack */ + } + return result; +} diff --git a/configure.in.bot b/configure.in.bot new file mode 100644 index 0000000..4f1129d --- /dev/null +++ b/configure.in.bot @@ -0,0 +1,11 @@ +dnl put here things which have to be done as very last part of configure + +if test "x$arts_audiolib_found" = "xno"; then + echo "" + echo "You're missing libaudiofile. aRts won't be able to load or play" + echo "any samples without it, so please install it." + echo "Have a look at http://www.68k.org/~michael/audiofile/ or find a" + echo "binary package for your platform." + echo "" + all_tests=bad +fi diff --git a/configure.in.in b/configure.in.in new file mode 100644 index 0000000..2cb7d6f --- /dev/null +++ b/configure.in.in @@ -0,0 +1,851 @@ +# Original Author was Kalle@kde.org +# I lifted it in some mater. (Stephan Kulow) +# I used much code from Janos Farkas + +dnl Process this file with autoconf to produce a configure script. +AC_INIT(acinclude.m4) dnl a source file from your sub dir + +dnl This is so we can use kde-common +AC_CONFIG_AUX_DIR(admin) + +dnl right now: install aRts in the same prefix as KDE3.x currently +KDE_SET_PREFIX_CORE + +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM + +dnl Version (we /might/ want to use libtool versioning, too) +ARTS_MAJOR_VERSION=1 +ARTS_MINOR_VERSION=5 +ARTS_MICRO_VERSION=10 +ARTS_VERSION=$ARTS_MAJOR_VERSION.$ARTS_MINOR_VERSION.$ARTS_MICRO_VERSION + +dnl Automake doc recommends to do this only here. (Janos) +AM_INIT_AUTOMAKE(arts, $ARTS_VERSION) dnl searches for some needed programs + +AC_PROG_INSTALL + +dnl generate the config header +AM_CONFIG_HEADER(config.h) dnl at the distribution this done + +dnl Checks for programs. +AC_CHECK_COMPILERS +AC_LIBLTDL_CONVENIENCE + +AC_ENABLE_SHARED(yes) +AC_ENABLE_STATIC(no) +KDE_PROG_LIBTOOL + +AC_LANG_SAVE +AC_LANG_C +KDE_LIB_LTDL +AC_LANG_RESTORE + +# this checks for --with-extra-libs +KDE_CHECK_EXTRA_LIBS +KDE_MISC_TESTS +dnl KDE_CHECK_LIBDL +dnl AC_PROG_LIBTOOL +KDE_CHECK_QT_DIRECT +KDE_ENABLE_HIDDEN_VISIBILITY + +dnl for NLS support. Call them in this order! +dnl WITH_NLS is for the po files, GNU_GETTEXT for the sources +dnl AM_KDE_WITH_NLS +dnl AM_KDE_GNU_GETTEXT + +dnl Checks for header files. +KDE_CHECK_STL +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h sys/cdefs.h fnmatch.h sysent.h strings.h sys/stat.h sys/select.h sys/socket.h linux/socket.h socketbits.h sigaction.h paths.h malloc.h monetary.h sys/param.h limits.h sys/mnttab.h mntent.h fstab.h) + +KDE_CHECK_HEADERS(sys/soundcard.h) + +dnl Checks for libraries. +AC_BASE_PATH_KDE([don't test]) dnl arts is a special case +AC_CHECK_LIB(compat, main, [LIBCOMPAT="-lcompat"]) dnl for FreeBSD +AC_CHECK_LIB(util, main, [LIBUTIL="-lutil"]) dnl for FreeBSD +AC_CHECK_FUNC(sem_init, , AC_CHECK_LIB(rt, sem_init, [LIBSEM="-lrt"])) + +AM_CONDITIONAL(HAVE_LIBJPEG, test -n "$LIBJPEG" ) +AM_CONDITIONAL(HAVE_LIBPNG, test -n "$LIBPNG" ) +AM_CONDITIONAL(HAVE_LIBTIFF, test -n "$LIBTIFF") + +# configure would do this very late. Too late for us! +test "x$prefix" = xNONE && prefix=$ac_default_prefix + +AC_DEFINE_UNQUOTED(KDEDIR, "$prefix", [The prefix to use as fallback]) + +ac_cpp_safe=$ac_cpp +ac_cpp='$CXXCPP $CPPFLAGS $X_INCLUDES' +KDE_CHECK_HEADERS(X11/ICE/ICElib.h) +ac_cpp=$ac_cpp_safe + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_TIME +AC_C_BIGENDIAN + +dnl check if the compiler has bool +AC_CHECK_BOOL +dnl AC_CHECK_GNU_EXTENSIONS + +dnl Checks for library functions. +AC_CHECK_FUNCS(socket snprintf vsnprintf seteuid setegid random strfmon stpcpy mkstemp setmntent gettimeofday vasprintf) +AC_FUNC_VFORK +AC_CHECK_USLEEP +AC_CHECK_SETENV +AC_CHECK_GETHOSTNAME +AC_CHECK_RANDOM +AC_CHECK_S_ISSOCK +AC_CHECK_SOCKLEN_T + +dnl output files +AC_SUBST(x_includes) +AC_SUBST(x_libraries) +AC_SUBST(LIBSOCKET) +AC_SUBST(LIBCOMPAT) +AC_SUBST(LIBUTIL) +AC_SUBST(LIBSEM) +AC_SUBST(LIBICE) + +all_includes="$all_includes $INCLTDL" +AC_SUBST(all_includes) + +AC_SUBST(EXTRA_SUBDIRS) + +topdir=`cd $srcdir && pwd` +ac_configure_args="$ac_configure_args --with-auxdir=$topdir/admin" + +CXXFLAGS="$CXXFLAGS $USE_RTTI" + +dnl---------------------------------------------------------------------------- +dnl aRts specific configure tests +dnl +dnl Check for libaudioio (which can be used to get solaris audio support) +AC_DEFUN([AC_CHECK_LIBAUDIOIO], +[ + ac_ldflags_save="$LDFLAGS" + ac_CPPFLAGS_save="$CPPFLAGS" + LDFLAGS="$all_libraries $LDFLAGS" + CPPFLAGS="$CPPFLAGS $all_includes" + arts_libaudioio_found=no + AC_LANG_SAVE + AC_LANG_C + kde_have_libaudioio=no + AC_CHECK_HEADER(libaudioio.h, + [ + kde_have_libaudioio=yes + ]) + if test "x$kde_have_libaudioio" = "xyes"; then + AC_CHECK_LIB(audioio,AudioIOGetVersion,[ + dnl LDFLAGS in case it's in KDEDIR/lib + LIBAUDIOIO="$LDFLAGS -laudioio" + AC_DEFINE(HAVE_LIBAUDIOIO, 1, + [Define if you have libaudioIO (required if you want to have libaudioio support)]) + arts_libaudioio_found=yes + ]) + fi + AC_SUBST(LIBAUDIOIO) + AC_LANG_RESTORE + CPPFLAGS="$ac_CPPFLAGS_save" + LDFLAGS="$ac_ldflags_save" +]) + +dnl aRts specific configure tests +dnl +dnl Check for libaudio (which can be used to get network audio support) +AC_DEFUN([AC_CHECK_LIBAUDIONAS], +[ + ac_ldflags_save="$LDFLAGS" + ac_CPPFLAGS_save="$CPPFLAGS" + LDFLAGS="$all_libraries $LDFLAGS" + CPPFLAGS="$CPPFLAGS $all_includes" + + AC_LANG_SAVE + AC_LANG_C + arts_libaudionas_include=no + AC_CHECK_HEADER(audio/audiolib.h, + [ + arts_libaudionas_include=yes + ]) + if test "x$arts_libaudionas_include" = "xyes"; then + AC_CHECK_LIB(audio,AuOpenServer,[ + dnl LDFLAGS in case it's in KDEDIR/lib + LIBAUDIONAS="-laudio -lXt" + LIBAUDIONAS_LDFLAGS="$LDFLAGS" + AC_DEFINE(HAVE_LIBAUDIONAS, 1, + [Define if you have libaudio (required if you want to have NAS support)]) + ]) + fi + AC_SUBST(LIBAUDIONAS) + AC_SUBST(LIBAUDIONAS_LDFLAGS) + AC_LANG_RESTORE + CPPFLAGS="$ac_CPPFLAGS_save" + LDFLAGS="$ac_ldflags_save" +]) + +dnl Check for libesd (for EsounD support) +AC_DEFUN([AC_CHECK_LIBESD], +[ + ac_ldflags_save="$LDFLAGS" + ac_CPPFLAGS_save="$CPPFLAGS" + LDFLAGS="$all_libraries $LDFLAGS" + CPPFLAGS="$CPPFLAGS $all_includes" + + AC_LANG_SAVE + AC_LANG_C + arts_libaudionas_include=no + AC_CHECK_HEADER(esd.h, + [ + arts_libesd_include=yes + ]) + if test "x$arts_libesd_include" = "xyes"; then + AC_CHECK_LIB(esd,esd_open_sound,[ + dnl LDFLAGS in case it's in KDEDIR/lib + LIBESD="-lesd" + LIBESD_LDFLAGS="$LDFLAGS" + AC_DEFINE(HAVE_LIBESD, 1, + [Define if you have libesd (required if you want EsounD support)]) + ]) + fi + AC_SUBST(LIBESD) + AC_SUBST(LIBESD_LDFLAGS) + AC_LANG_RESTORE + CPPFLAGS="$ac_CPPFLAGS_save" + LDFLAGS="$ac_ldflags_save" +]) + +dnl libaudiofile is used for loading wave files +AC_DEFUN([AC_CHECK_LIBAUDIOFILE], +[ + ac_ldflags_save="$LDFLAGS" + ac_CPPFLAGS_save="$CPPFLAGS" + LDFLAGS="$all_libraries $LDFLAGS" + CPPFLAGS="$CPPFLAGS $all_includes" + arts_audiolib_found=no + dnl WAV reading + AC_LANG_SAVE + AC_LANG_C + kde_has_audio_lib=no + AC_CHECK_HEADER(audiofile.h, + [ + kde_has_audio_lib=yes + ]) + if test "x$kde_has_audio_lib" = "xyes"; then + KDE_CHECK_LIB(audiofile,afOpenFile,[ + dnl LDFLAGS in case it's in KDEDIR/lib + LIBAUDIOFILE="-laudiofile" + LIBAUDIOFILE_LDFLAGS="$LDFLAGS" + AC_DEFINE(HAVE_LIBAUDIOFILE, 1, + [Define if you have libaudiofile (required for playing wavs with aRts)]) + arts_audiolib_found=yes + ]) + fi + AC_SUBST(LIBAUDIOFILE) + AC_SUBST(LIBAUDIOFILE_LDFLAGS) + AC_LANG_RESTORE + CPPFLAGS="$ac_CPPFLAGS_save" + LDFLAGS="$ac_ldflags_save" +]) + + +dnl check if sgi libaudio is present +AC_DEFUN([AC_CHECK_SGILIBAUDIO], +[ + ac_ldflags_save="$LDFLAGS" + ac_CPPFLAGS_save="$CPPFLAGS" + LDFLAGS="$all_libraries $LDFLAGS" + CPPFLAGS="$CPPFLAGS $all_includes" + + dnl SGI libaudio (required on IRIX) + AC_LANG_SAVE + AC_LANG_C + arts_dmedia_include=no + AC_CHECK_HEADER(dmedia/audio.h, + [ + arts_dmedia_include=yes + ]) + if test "x$arts_dmedia_include" = "xyes"; then + KDE_CHECK_LIB(audio,alOpenPort,[ + SGILIBAUDIO="-laudio" + AC_DEFINE(HAVE_SGILIBAUDIO, 1, + [Define if you have libaudio (required for sound i/o on IRIX)]) + ]) + fi + AC_SUBST(SGILIBAUDIO) + AC_LANG_RESTORE + CPPFLAGS="$ac_CPPFLAGS_save" + LDFLAGS="$ac_ldflags_save" +]) + +dnl check if we want to build MAS support +AC_DEFUN([AC_CHECK_LIBMAS], +[ +AC_PATH_PROG(MAS_CONFIG, mas-config, no) + +if test "$MAS_CONFIG" != "no"; then + AC_DEFINE(HAVE_LIBMAS, 1, + [Define if you have libmas (required if you want MAS support)]) + MAS_CFLAGS="`$MAS_CONFIG --cflags`" + tmp_mas_libs="`$MAS_CONFIG --libs` -lmas_jrtp" + MAS_LDFLAGS="`for i in $tmp_mas_libs; do echo $i; done |grep ^-L`" + MAS_LDFLAGS="$MAS_LDFLAGS `for i in $tmp_mas_libs; do echo $i; done |grep ^-L |sed s/^-L/-R/g`" + LIBMAS="$MAS_LDFLAGS" + for i in $tmp_mas_libs; do LIBMAS="$LIBMAS `echo $i |grep ^-l`"; done +fi +AC_SUBST(MAS_CFLAGS) +AC_SUBST(MAS_LDFLAGS) +AC_SUBST(LIBMAS) + +]) + +dnl Posix realtime scheduling - this is helpful if you want arts to run with +dnl higher priority than everthing else + +AC_DEFUN([ARTS_TRY_LINK_POSIX_REALTIME], +[ +AC_TRY_LINK([ +#include +], +[ +sched_getscheduler(0); +], +arts_realtime_sched=yes, +arts_realtime_sched=no) +]) + +AC_DEFUN([AC_CHECK_REALTIME_SCHED], +[ +AC_MSG_CHECKING([for posix realtime scheduling support]) +save_LIBS="$LIBS" +LIBPOSIX4="" +ARTS_TRY_LINK_POSIX_REALTIME +if test "x$arts_realtime_sched" = "xno"; then + LIBS="$LIBS -lposix4" + ARTS_TRY_LINK_POSIX_REALTIME + if test "x$arts_realtime_sched" = "xyes"; then + LIBPOSIX4="-lposix4" + fi +fi +LIBS="$save_LIBS" +AC_SUBST(LIBPOSIX4) +AC_MSG_RESULT($arts_realtime_sched) + +if test "x$arts_realtime_sched" = "xyes"; then + AC_DEFINE(HAVE_REALTIME_SCHED,1, + [Define if your system supports realtime scheduling]) +fi +]) + +dnl Type of the ioctl function test - after some tries, it seems that this +dnl not required for Linux vs. FreeBSD (for which this test was written), and +dnl that only the Linux documentation claims that it has an "int" as second +dnl argument. But maybe there will pop up systems for which the signature +dnl differs, later. + +AC_DEFUN([AC_CHECK_IOCTL_TYPE], +[ + AC_MSG_CHECKING([ioctl type]) + AC_CACHE_VAL(ac_cv_ioctl_type, + [ + AC_LANG_SAVE + AC_LANG_C + + AC_TRY_COMPILE( + [ + #include + #include + int ioctl(int d, int request,...); + ], + [ + ], + ac_cv_ioctl_type=1) + AC_TRY_COMPILE( + [ + #include + #include + int ioctl(int d, unsigned long request,...); + ], + [ + ], + ac_cv_ioctl_type=2) + AC_TRY_COMPILE( + [ + #include + #include + int ioctl(int d, unsigned long int request,...); + ], + [ + ], + ac_cv_ioctl_type=3) + AC_LANG_RESTORE + ]) + AC_MSG_RESULT($ac_cv_ioctl_type) + + +if test "$ac_cv_ioctl_type" = "1"; then + AC_DEFINE(HAVE_IOCTL_INT_INT_DOTS,1, + [Define if ioctl is declared as int ioctl(int d, int request,...)]) +fi +if test "$ac_cv_ioctl_type" = "2"; then + AC_DEFINE(HAVE_IOCTL_INT_ULONG_DOTS,2, + [Define if ioctl is declared as int ioctl(int d, unsigned long request,...)]) +fi +if test "$ac_cv_ioctl_type" = "3"; then + AC_DEFINE(HAVE_IOCTL_INT_ULONGINT_DOTS,3, + [Define if ioctl is declared as int ioctl(int d, unsigned long int request,...)]) +fi +]) + +dnl check whether we can do rouding using asm optimization + +AC_DEFUN([AC_CHECK_X86_FLOAT_INT], +[ +AC_MSG_CHECKING([for x86 float to int conversions]) +AC_CACHE_VAL(ac_cv_x86_float_int, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_LINK([ +#if defined(__i386__) +static inline long QRound (float inval) +{ + long ret; + __asm__ ("fistpl %0" : "=m" (ret) : "t" (inval) : "st"); + return ret; +} +#else +error +#endif +], +[ +long i = QRound(41.93); /* should be 42 */ +], +ac_cv_x86_float_int=yes, +ac_cv_x86_float_int=no) +AC_LANG_RESTORE +]) +AC_MSG_RESULT($ac_cv_x86_float_int) +if test "x$ac_cv_x86_float_int" = "xyes"; then + AC_DEFINE(HAVE_X86_FLOAT_INT,1, + [Define if you want to use optimized x86 float to int conversion code]) +fi +]) + +dnl check if the assembler supports SSE instructions +AC_DEFUN([AC_CHECK_X86_SSE], +[ +AC_MSG_CHECKING([for x86 SSE instructions]) +AC_CACHE_VAL(ac_cv_x86_sse, +[ +AC_TRY_COMPILE(, +[ +#if defined(__GNUC__) && defined(__i386__) +__asm__("movups %xmm0, (%esp)"); +#else +/* IRIX's cc treats #error as a warning, make sure it errors out here */ +error Not gcc on x86 +#endif +], +ac_cv_x86_sse=yes, +ac_cv_x86_sse=no) +]) +AC_MSG_RESULT($ac_cv_x86_sse) +if test "x$ac_cv_x86_sse" = "xyes"; then + AC_DEFINE(HAVE_X86_SSE,1, + [Define if your assembler supports x86 SSE instructions]) +fi +]) + +dnl check whether we should try to emulate stdio fopen/fclose via +dnl glibc facilities (this *really* depends on glibc internals) + +AC_DEFUN([AC_CHECK_ARTSDSP_STDIO_EMU], +[ +AC_MSG_CHECKING([for stdio emulation in artsdsp]) +AC_CACHE_VAL(ac_cv_artsdsp_stdio_emu, +[ +AC_LANG_SAVE +AC_LANG_C +AC_TRY_LINK([ +#define _GNU_SOURCE +#include +], +[ + cookie_io_functions_t fns = { 0, 0, 0, 0 }; + struct fd_cookie *fdc = 0; + FILE *out = fopencookie (fdc,"w", fns); + out->_fileno = 0; +], +ac_cv_artsdsp_stdio_emu=yes, +ac_cv_artsdsp_stdio_emu=no) +]) +AC_LANG_RESTORE +AC_MSG_RESULT($ac_cv_artsdsp_stdio_emu) +if test "x$ac_cv_artsdsp_stdio_emu" = "xyes"; then + AC_DEFINE(HAVE_ARTSDSP_STDIO_EMU,1, + [Define if you want to use glibc facilities to emulate stdio accesses in artsdsp]) +fi +]) + +dnl call the tests +AC_ARG_WITH(libaudioio, + [AC_HELP_STRING(--with-libaudioio, + [enable support for libaudioio @<:@default=check@:>@])], + [], with_libaudioio=check) + +if test "x$with_libaudioio" != xno; then + AC_CHECK_LIBAUDIOIO + + if test "x$with_libaudioio" != xcheck && test -z "$LIBAUDIOIO"; then + AC_MSG_FAILURE([--with-libaudioio was given, but test for libaudioio failed]) + fi +fi + +AC_ARG_WITH(nas, + [AC_HELP_STRING(--with-nas, + [enable support for NAS @<:@default=check@:>@])], + [], with_nas=check) + +if test "x$with_nas" != xno; then + AC_CHECK_LIBAUDIONAS + + if test "x$with_nas" != xcheck && test -z "$LIBAUDIONAS"; then + AC_MSG_FAILURE([--with-nas was given, but test for NAS failed]) + fi +fi + +AC_ARG_WITH(esd, + [AC_HELP_STRING(--with-esd, + [enable support for EsounD @<:@default=check@:>@])], + [], with_esd=check) + +if test "x$with_esd" != xno; then + AC_CHECK_LIBESD + + if test "x$with_esd" != xcheck && test -z "$LIBESD"; then + AC_MSG_FAILURE([--with-esd was given, but test for EsounD failed]) + fi +fi + +AC_ARG_WITH(audiofile, + [AC_HELP_STRING(--with-audiofile, + [enable support for audiofile @<:@default=check@:>@])], + [], with_audiofile=check) + +if test "x$with_audiofile" != xno; then + AC_CHECK_LIBAUDIOFILE + + if test "x$with_audiofile" != xcheck && test -z "$LIBAUDIOFILE"; then + AC_MSG_FAILURE([--with-audiofile was given, but test for audiofile failed]) + fi +fi +AM_CONDITIONAL(HAVE_WAVSUPPORT, test -n "$LIBAUDIOFILE") + +AC_ARG_WITH(sgilibaudio, + [AC_HELP_STRING(--with-sgilibaudio, + [enable support for SGI libaudio @<:@default=check@:>@])], + [], with_sgilibaudio=check) + +if test "x$with_sgilibaudio" != xno; then + AC_CHECK_SGILIBAUDIO + + if test "x$with_sgilibaudio" != xcheck && test -z "$SGILIBAUDIO"; then + AC_MSG_FAILURE([--with-sgilibaudio was given, but test for SGI libaudio failed]) + fi +fi + +AC_ARG_WITH(mas, + [AC_HELP_STRING(--with-mas, + [enable support for MAS @<:@default=check@:>@])], + [], with_mas=check) + +if test "x$with_mas" != xno; then + AC_CHECK_LIBMAS + + if test "x$with_mas" != xcheck && test -z "$LIBMAS"; then + AC_MSG_FAILURE([--with-mas was given, but test for MAS failed]) + fi +fi + +AC_CHECK_REALTIME_SCHED +AC_CHECK_GETDOMAINNAME +AC_CHECK_IOCTL_TYPE +AC_CHECK_X86_FLOAT_INT +AC_CHECK_X86_SSE +AC_CHECK_ARTSDSP_STDIO_EMU +KDE_CHECK_THREADING + +dnl somewhat more deeply nested template code than gcc understands by default +if test "$GXX" = "yes"; then + KDE_CHECK_COMPILER_FLAG(ftemplate-depth-99, + [ + CXXFLAGS="$CXXFLAGS -ftemplate-depth-99" + ]) +fi + +dnl check for ALSA audio support +arts_with_alsa=yes +AC_ARG_WITH(alsa, [ --with-alsa enable aRts ALSA support], +[arts_with_alsa=$withval]) + +if test "$arts_with_alsa" = "yes"; then +AC_DEFUN([AC_CHECK_LIBASOUND], +[ + ac_ldflags_save="$LDFLAGS" + LDFLAGS="$all_libraries $LDFLAGS" + kde_has_asoundlib=no + + AC_CHECK_HEADERS([ sys/asoundlib.h alsa/asoundlib.h ], + [ + kde_has_asoundlib=yes + ]) + + dnl trial and error version check for ALSA 0.5.x / ALSA 0.9.x + AC_LANG_SAVE + AC_LANG_C + if test "x$kde_has_asoundlib" = "xyes"; then + AC_TRY_COMPILE([ + #include "confdefs.h" + #ifdef HAVE_SYS_ASOUNDLIB_H + #include + #endif + #ifdef HAVE_ALSA_ASOUNDLIB_H + #include + #endif + ],[ + #if (SND_LIB_MAJOR == 0) && (SND_LIB_MINOR == 9) + /* we have ALSA 0.9.x */ + #else + #error not ALSA 0.9.x + #endif + ], + kde_has_alsa_0_9=yes, + kde_has_alsa_0_9=no) + fi + + if test "x$kde_has_asoundlib" = "xyes"; then + AC_TRY_COMPILE([ + #include "confdefs.h" + #ifdef HAVE_SYS_ASOUNDLIB_H + #include + #endif + #ifdef HAVE_ALSA_ASOUNDLIB_H + #include + #endif + ],[ + #if (SND_LIB_MAJOR == 1) && (SND_LIB_MINOR == 0) + /* we have ALSA 1.x */ + #else + #error not ALSA 1.x + #endif + ], + kde_has_alsa_1_0=yes, + kde_has_alsa_1_0=no) + fi + + if test "x$kde_has_asoundlib" = "xyes"; then + AC_TRY_COMPILE([ + #include "confdefs.h" + #ifdef HAVE_SYS_ASOUNDLIB_H + #include + #endif + #ifdef HAVE_ALSA_ASOUNDLIB_H + #include + #endif + ],[ + #if (SND_LIB_MAJOR == 0) && (SND_LIB_MINOR == 5) + /* we have ALSA 0.5.x */ + #else + #error not ALSA 0.5.x + #endif + ], + kde_has_alsa_0_5=yes, + kde_has_alsa_0_5=no) + fi + AC_LANG_RESTORE + + if test "x$kde_has_asoundlib" = "xyes"; then + AC_CHECK_LIB(asound,snd_seq_create_simple_port,[ + if test "x$kde_has_alsa_0_5" = "xyes"; then + LIBASOUND="-lasound" + AC_DEFINE(HAVE_LIBASOUND, 1, + [Define if you have libasound.so.1 (required for ALSA 0.5.x support)]) + fi + if test "x$kde_has_alsa_0_9" = "xyes"; then + LIBASOUND="-lasound" + AC_DEFINE(HAVE_LIBASOUND2, 1, + [Define if you have libasound.so.2 (required for ALSA 0.9.x support)]) + AC_CHECK_LIB(asound,snd_pcm_resume,[ + AC_DEFINE(HAVE_SND_PCM_RESUME, 1, + [Define if libasound has snd_pcm_resume()])]) + fi + if test "x$kde_has_alsa_1_0" = "xyes"; then + LIBASOUND="-lasound" + AC_DEFINE(HAVE_LIBASOUND2, 1, + [Define if you have libasound.so.2 (required for ALSA 0.9.x/1.x support)]) + AC_DEFINE(ALSA_PCM_OLD_SW_PARAMS_API, 1, + [Define if you have alsa 1.x]) + AC_DEFINE(ALSA_PCM_OLD_HW_PARAMS_API, 1, + [Define if you have alsa 1.x]) + AC_CHECK_LIB(asound,snd_pcm_resume,[ + AC_DEFINE(HAVE_SND_PCM_RESUME, 1, + [Define if libasound has snd_pcm_resume()])]) + fi + ]) + fi + AC_SUBST(LIBASOUND) + LDFLAGS="$ac_ldflags_save" +]) +AC_CHECK_LIBASOUND +fi + +AC_SUBST(LIBASOUND) + +dnl check for IRIX audio support +AC_MSG_CHECKING([for IRIX]) +if test `uname` = "IRIX" -o `uname` = "IRIX64" ; then + AC_DEFINE(HAVE_IRIX, 1, [Define if you compile under IRIX]) + AC_MSG_RESULT("yes") +else + AC_MSG_RESULT("no") +fi + +dnl check wether we want to use libcsl style sound I/O +AC_ARG_ENABLE(csl, +[ --enable-csl enable libcsl style sound I/O for aRts], +[arts_want_csl="$enableval"],[arts_want_csl="no"]) + +if test "$arts_want_csl" = "yes"; then + LIBCSL="-lcsl" + AC_DEFINE(HAVE_LIBCSL, 1, + [Define if you have libcsl (required if you want to have CSL support)]) +else + LIBCSL="" +fi +AC_SUBST(LIBCSL) + +dnl Check for pkg-config +AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + +if test "$PKG_CONFIG" = "no"; then + AC_MSG_ERROR([ +This package requires pkg-config. +]) +fi + +dnl Check for Glib-2.0 +# GLIB_CFLAGS: cflags for compiling glib dependant sources +# GLIB_LIBADD: glib libraries (-l options) +# GLIB_LDFLAGS: flags containing path to glib libraries (-L options) + +GLIB_PACKAGES="gmodule-2.0 gthread-2.0" +GLIB_VERSION="1.3.3" +AC_MSG_CHECKING(for GLib-2.0 (at least $GLIB_VERSION)) + +if $PKG_CONFIG --atleast-pkgconfig-version 0.15 ; then + if $PKG_CONFIG --atleast-version $GLIB_VERSION $GLIB_PACKAGES >/dev/null 2>&1 ; then + GLIB_CFLAGS="`$PKG_CONFIG --cflags $GLIB_PACKAGES`" + GLIB_LIBADD="`$PKG_CONFIG --libs-only-l --libs-only-other $GLIB_PACKAGES`" + GLIB_LDFLAGS="`$PKG_CONFIG --libs-only-L $GLIB_PACKAGES`" + AC_MSG_RESULT(yes) + fi +else + if $PKG_CONFIG --atleast-version $GLIB_VERSION $GLIB_PACKAGES >/dev/null 2>&1 ; then + GLIB_CFLAGS="`$PKG_CONFIG --cflags $GLIB_PACKAGES`" + GLIB_LIBADD="`$PKG_CONFIG --libs $GLIB_PACKAGES`" + GLIB_LDFLAGS="`$PKG_CONFIG --libs-only-L $GLIB_PACKAGES`" + AC_MSG_RESULT(yes) + AC_MSG_WARN([you may need to run make LDFLAGS=-pthread to compile arts]) + fi +fi + +if test -z "$GLIB_LIBADD"; then + AC_MSG_RESULT(not installed) + AC_ERROR([ + Please install glib-2.0 (see http://www.gtk.org). + ]) + DO_NOT_COMPILE="$DO_NOT_COMPILE gmcop" +fi + +CPPFLAGS="$CPPFLAGS $GLIB_CFLAGS" +CFLAGS="$CFLAGS $GLIB_CFLAGS" + +AC_SUBST(GLIB_CFLAGS) +AC_SUBST(GLIB_LIBADD) +AC_SUBST(GLIB_LDFLAGS) + +AC_ARG_WITH(jack, + [AC_HELP_STRING(--with-jack, + [enable support for Jack @<:@default=check@:>@])], + [], with_jack=check) + +if test "x$with_jack" != xno; then + AC_MSG_CHECKING(for Jack Audio Connection Kit) + if $PKG_CONFIG --atleast-version 0.90 jack >/dev/null 2>&1 ; then + JACK_CFLAGS="`$PKG_CONFIG --cflags jack`" + JACK_LIBADD="`$PKG_CONFIG --libs-only-l jack`" + JACK_LDFLAGS="`$PKG_CONFIG --libs-only-L jack`" + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_LIBJACK, 1, + [Define if you have libjack (required if you want Jack support)]) + else + AC_MSG_RESULT(not installed) + fi + AC_SUBST(JACK_CFLAGS) + AC_SUBST(JACK_LIBADD) + AC_SUBST(JACK_LDFLAGS) + + if test "x$with_jack" != xcheck && test -z "$JACK_LIBADD"; then + AC_MSG_FAILURE([--with-jack was given, but test for Jack failed]) + fi +fi + +dnl OpenBSD requires an -lossaudio and soundcard.h to provide OSS audio I/O +AC_CHECK_HEADERS(soundcard.h) +AC_CHECK_LIB(ossaudio, _oss_ioctl, [LIBOSSAUDIO="-lossaudio"]) +AC_SUBST(LIBOSSAUDIO) + +AM_CONFIG_HEADER(mcop/arts_export.h) +AM_CONFIG_HEADER(artsc/artsc_export.h) + +dnl Don't remove ! +dnl AC_OUTPUT(artsc/artsc-config) + +dnl Check if we are building as part of KDE. Arts can also be built as +dnl a standalone snapshot in which case KDE may not be present and things +dnl that depend on KDE should not be built. +dnl AC_MSG_CHECKING(if building standalone aRts snapshot without KDE) +dnl if test "$DCOPIDL" = ""; then +dnl AC_MSG_RESULT(yes) +dnl ARTS_BUILD_KDE="" +dnl MOC="true" +dnl DCOPIDL="true" +dnl DCOPIDL2CPP="true" +dnl AC_SUBST(MOC) +dnl AC_SUBST(DCOPIDL) +dnl AC_SUBST(DCOPIDL2CPP) +dnl else +dnl AC_MSG_RESULT(no) +dnl if test "x$kde_use_qt_emb" = "xyes"; then +dnl ARTS_BUILD_KDE="qtmcop kde knotify message" +dnl else +dnl ARTS_BUILD_KDE="x11 qtmcop kde knotify message" +dnl fi +dnl fi +dnl AC_SUBST(ARTS_BUILD_KDE) + +MCOPIDL='$(top_builddir)/mcopidl/mcopidl' +AC_SUBST(MCOPIDL) + +AC_SUBST(ARTS_MAJOR_VERSION) +AC_SUBST(ARTS_MINOR_VERSION) +AC_SUBST(ARTS_MICRO_VERSION) +AC_SUBST(ARTS_VERSION) + +dnl Don't remove ! +dnl AC_OUTPUT(artsc/artsdsp) +dnl AC_OUTPUT(soundserver/artsversion-new.h) +dnl AC_OUTPUT(flow/gsl/gslconfig.h) + diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..a4c137b --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = NEWS README TODO diff --git a/doc/NEWS b/doc/NEWS new file mode 100644 index 0000000..0b68fe4 --- /dev/null +++ b/doc/NEWS @@ -0,0 +1,58 @@ +aRts-1.2.0: +- added EsounD support +- fixed autosuspend in conjunction with full duplex + +aRts-1.1.0: +- added functions to StdSynthModule to find if/how many other modules are + connected to the inputs and outputs of yourself + +aRts-1.0.0: +- full duplex fixed + +aRts-0.7.0: +- recording in the C API +- new interface for video embedding (Arts::VideoPlayObject) via X11 embedding +- threaded oss audio i/o (-a toss) which works better with some kernel drivers +- irix audio i/o method (-a sgi) +- ALSA-0.9.0 support +- Preference=N lines in .mcopclass files make it possible to to choose one + implementation over another if they both implement the same interface + +aRts-0.6.1: +- new artsdsp -s (single threaded) option for compatibility to more programs + (for instance netscape) +- ALSA-0.9.0 support +- bugfixes: artsdsp/artsc rpath fix, alsa crash without soundcard fixed, md5 + cookie loading, oss driver endianess issue, compile fixes + +aRts-0.6.0: +- new interfaces (Arts::InputStream, Arts::StreamPlayObject) for decoding + streams of data with PlayObjects (rather than just files) +- new Arts::PitchablePlayObject for changing playing speed/pitch +- support for streaming of data from kioslaves into PlayObjects +- dynamic implementation of classes/attributes (Arts::DynamicSkeleton) + +(some of the items that are listed in aRts-0.6.0 have been done somewhere + between 0.4 and 0.6 and only now found its way into this) + +aRts-0.5.4: +- fix random segfaults on solaris + +aRts-0.5.3: +- performance improvement for aRts midi instruments (bus code rewritten) +- structures designed by artsbuilder can be used modules in structures again + (and elsewhere), via generic Arts::Loader's + +aRts-0.5.2: +- threading support (libmcop_mt) +- glib-2.0 mainloop integration (libgmcop) +- KArtsWidget makes it easy to use Arts::Widget implementations in conjunction + with qt widgets (i.e. no extra window), this also removes the annoying extra + window in artscontrol +- generic gui factory used by noatun and artscontrol to create effect guis + +================================================================================ +This file starts in the middle of nowhere, because it hasn't always been +here. But please update this if you do bigger changes (fixing a spelling +error in a comment probably doesn't count, doing one of the TODO items +most certainly does). diff --git a/doc/README b/doc/README new file mode 100644 index 0000000..60a3beb --- /dev/null +++ b/doc/README @@ -0,0 +1,5 @@ +All of the aRts documentation is now in "The aRts Handbook" which is +in KDE DocBook format, part of kdemultimedia. It should be found on a +KDE system in $KDEDIR/share/doc/HTML/default/artsbuilder/index.html. + +An on-line version can be found at http://www.arts-project.org/doc/handbook diff --git a/doc/TODO b/doc/TODO new file mode 100644 index 0000000..37f856e --- /dev/null +++ b/doc/TODO @@ -0,0 +1,215 @@ +- fix problems with REGISTER_IMPLEMENTATION: + => sometimes, global constructors don't work, so we'd better get rid + of them entierly ; instead, an init function needs to be added to + dynamically loaded modules +- get rid of all error handling done by assert ; thus, one by one review + each assert if it can happen under any circumstances if yes, it needs + to be replaced by some other mechanism +- report errors properly if some component could not be loaded ; right + now, it fails within assert(skel) in generated code, which doesn't + help users much to debug the problem +- VERSION-INFO for modules? +- md5auth isn't initialized properly in conjunction with ARTS_SERVER +- make it possible to use C API and C++ API together +- FIXME: what to do about apps which are not threaded but nevertheless + want to use the engine? +- gsl: rounding should be used even for unsigned conversions + +## MCOP Core Infrastructure + +- offer sampleprecise timing +- resource management (i.e. locate resources like "samples" or "structures" + in a similar uniform way KDE does with KStandardDirs) +- check why adding thousand non-running objects degrades scheduling + performance quite a lot +- recursive scheduling again (with loops & cycles) +- obsoleting: use V2 implementations even if user requests a normal + implementation, since they have a newer version +- error notification for connection breaks - this would enable intelligent + clients to immediately know when something goes wrong, so they can terminate + sanely instead of crashing +- mcopidl: use unsigned char arrays instead of strings for inline marshalled + data in idl files - this will fix the "maximum string length" warnings and + while doing this improve space and speed +- try to clean up notification manager, code generation and _copy() _release() + style referencing across functions in notification and Dispatcher - the + alternatives seem to be even more automatic referencing magic, or freeing + objects only if the stack is empty (idle freeing) +- fix generated code for struct Foo { object bar; } +- fix fallback into higher namespaces, the following idl file should be accepted + module A { interface Z; module B { interface Y : Z { }; }; }; + +- debugging: if two alternating messages are emitted, the message compression + doesn't work, and the user will be flooded with debugging message, the X + server will crash, and so on - a possible strategy would be: + * make an always present MCOP object which can receive confirmations from + artsmessage + * start artsmessage as usual, but tell it about the MCOP object, so that + artsmessage can + - tell the MCOP object if it is done + - query the MCOP object for the repetition count of the message + * queue repeated messages as long as they are still visible on screen + +## aRts SoundServer + +- export configuration interfaces from the soundserver (so that + you can see and change the autosuspend timeout for instance) +- support multiple artsd instances on one computer (like multiple displays), + and think of a clever way to register them +- more support for different audio input/output methods (i.e. SDL) +- support channels != 2 +- expand capabilities of shell utils (making them eventually as powerful as + artscontrol, or better ;) +- make it possible to share a cookie between multiple hosts (like storing it + in nfs mounted home directory) +- make it possible for artsd to cascade audio input/output to another artsd +- ARTS_COOKIE, OSS_DEVICE + +## C API / artsdsp + +- implement an arts_stream_flush for writing half-written data packets + (useful for implementing SNDCTL_DSP_POST in artsdsp) +- move to CSL (CSL a new common sound layer, especially intended to be + compatible between Gnome and KDE) +- pkgconfig file +- it might be useful to allow clients on big endian systems to pass their + 16bit data with their native byte order - for compatibility with older API + versions, its required to make this an extra parameter + as an efficiency bonus, one could also make the wire representation then + 16bit big endian, which requires support from the sound server though; its + not required to implement the feature, though (which is probably useful + for application writers on 16bit big endian machines) + +## GUI Support + +- port visual objects (beginnings are in kdemultimedia/arts/gui) +- hbox, vbox +- gui generation +- hints via mcopidl + +## aRts Modules / Signal processing + +- midi recording for Brahms +- StereoEffectStack should support reordering (and probably listing) effects + (maybe backport noatuns version) +- hard disc recording +- allow progressive loading for wave files +- write blockwise caching (not requiring whole samples to be held in memory) +- akai support +- better interpolation / resampling +- the Resampler class should do big endian and float as inputs +- LADSPA support +- provide a GUI for stereo_pitch_shift + +## kcmarts + +- add restart option to the control panel, so that you can restart artsd easier + if it crashed (it never crashes, does it ;) - close #38417 when done + +## artsbuilder (and runtime) + +- allow to give additional parameters (like names for sample files to play) + through .arts-map files +- more examples (instruments, songs and such) +- gui editing (or should is it better to write a new editor for that) +- live editing of running structures +- component bar where you can choose components without going through all + these submenus +- property editor (like in delphi) +- support pressing "return" in the various dialogs and close them on doing + that (rather than always having to click "ok" with the mouse) +- i18n fixes + +## artscontrol + +- be able to remove midi ports *KDE2.2* +- add a mixer +- persistent state (Arts::Environment), so that the environment + can be restored on next login (or per song or something like that) +- edit .arts-map files visually + +## Optimization (this section contains various optimization ideas) + +- use no floats for adressing the fractional part in resampling but integers + (that will be MUCH faster) +- use short int for i16le resampling, instead of using a long and adding + sign manually (faster at least on athlon) +- tune the MCOP transfer protocol + * rewrite Buffer not to use vector to store data, but malloc'd blocks + * try to write "zero allocation" invocations, that means, try not to allocate + memory on performing an invocation. For instance Buffers could be kept in + pools, and be reused for further invocations, without the need to realloc + another memory block + * try to minimize the amount of copies of data, possibly even using something + like sharedmem to share data between the sending and receiving buffer + * hardcode frequently used calls in the Arts::Object interface + +## Documentation / Web + +- improve kdoc comments everywhere +- write incomplete sections in The aRts Handbook; improve formatting + +## Misc + +- put streamwise blocking into MCOP, see artscat.cc to read really ugly + source which lives without that feature +- implement plugins that transfer non-standard datatypes such as midi events, + video frames, fft packets, oscilloscope views, ... (which was impossible + with aRts on CORBA) +- make aRts run inside Brahms, KWave or your-favorite-other-app, to do + signal processing where it is needed (similar to AudioLogic Environment, + for instance) +- convince other people to use aRts, so that the usefulness of universal + plugins written for the API increases +- when being crazy, implement gatewaying from MCOP to DCOP, CORBA, XMLRPC + or whatever else might be useful + +## Interoperability (GNOME/C) + +- write a gartscontrol (in C) as native Gnome/Gtk app +- further work on CSL +- C language binding, based on glib +- mcopidl code generation for C + +## FlowSystem changes: + +It would be nice if the flowsystem became more "detached" from the normal +operation, making it ideally runnable in one or more thread dedicated for +audio processing. + +Flowsystem transactions: + + these group operation like: starting, stopping, connecting, disconnecting, + ... to transactions which will later (asynchronously) executed by the + flowsystem + +Example: problematic assertion + + assert(done[i] <= samples); /* synthschedule.cc:998 */ + + the problem with the assertion here is this - suppose some object reacts + in a way on some signal that will lead to the creation of new objects, + then those will get into the flowsystem, and we can't ultimately say + anything about how far these have been calculated so far + + extremely problematic in this context are so-called call-ins, that is + you do calculateBlock, and during this, the dispatcher mainloop gets + called for some reason (I hope that this does not happen currently) - + if that would hypothetically happen, then there the whole flowsystem + could get restructured (because i.e. ordinary midi events could be + processed) + +## libartskde + + * ensure that there is a pair of classes, like KAudioPlayStream and + KAudioRecordStream (or whatever they should be called) that can do + approximately what the C API can do + + * don't export implementation details in the API - for instance + KAudio(Play|Record)Stream should probably only inherit from QObject, and + only "use" some aRts objects to do the actual work - that way, they can + be changed/modified more easily afterwards + + * use Qt signals/slots as callbacks (at least as one possibility) for + "please produce new audio data" / "here is new audio data" - that way, + polling isn't necessary any longer diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000..53c455c --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,97 @@ +INCLUDES = -I$(top_srcdir)/mcop -I$(top_srcdir)/flow \ + -I$(top_builddir)/flow -I$(top_srcdir)/soundserver \ + -I$(top_builddir)/soundserver -I$(top_srcdir)/artsc \ + -I$(top_builddir)/mcop -I$(top_builddir)/artsc \ + $(all_includes) + +AM_LDFLAGS = $(all_libraries) +LDADD = $(top_builddir)/mcop/libmcop.la +FLOWLIBS = $(top_builddir)/flow/libartsflow.la + +####### Files + +check_PROGRAMS = helloserver helloclient referenceinfo \ + irdemo x11commtest streamsound hellomain flow artsctest \ + artscrec artsccat artscmt \ + dcasttest hellodynamic hellodynamic2 testasubsys testaggregation \ + playtofile testthreads testnothreads catfile testdhandle +helloserver_SOURCES = hello.cc helloserver.cc hello_impl.cc +helloclient_SOURCES = hello.cc helloclient.cc +hellodynamic_SOURCES = hello.cc hellodynamic.cc hello_impl.cc +hellodynamic2_SOURCES = hello.cc hellodynamic2.cc +referenceinfo_SOURCES = referenceinfo.cc + +testdhandle_SOURCES = testdhandle.cc +testdhandle.o: ../soundserver/soundserver.h ../flow/artsflow.h +testdhandle_LDADD = $(FLOWLIBS) \ + $(top_builddir)/soundserver/libsoundserver_idl.la \ + $(top_builddir)/flow/gslpp/libgslpp.la + +irdemo_SOURCES = irdemo.cc +x11commtest_SOURCES = x11commtest.cc +hellomain_SOURCES = hellomain.cc hello.cc hello_impl.cc + +testasubsys_SOURCES = testasubsys.cc +testasubsys_LDADD = $(FLOWLIBS) + +## testthreads/testnothreads: +## if we link testthreads.cc against libmcop_mt, it will be able to use +## real threading, if we don't, we won't +testthreads_SOURCES = testthreads.cc +testthreads_LDFLAGS = $(LDFLAGS) +testthreads_LDADD = $(top_builddir)/mcop_mt/libmcop_mt.la +testnothreads_SOURCES = testthreads.cc + +testaggregation_SOURCES = aggregation.cc testaggregation.cc + +flow_LDADD = $(FLOWLIBS) +flow_SOURCES = flow.cc + +streamsound_LDADD = $(FLOWLIBS) \ + $(top_builddir)/soundserver/libsoundserver_idl.la +streamsound_SOURCES = streamsound.cc + +dcasttest_LDADD = $(FLOWLIBS) \ + $(top_builddir)/soundserver/libsoundserver_idl.la +dcasttest_SOURCES = dcasttest.cc + +artsctest_LDADD = $(top_builddir)/artsc/libartsc.la +artsctest_SOURCES = artsctest.c + +artsccat_LDADD = $(top_builddir)/artsc/libartsc.la +artsccat_SOURCES = artsccat.c + +artscrec_LDADD = $(top_builddir)/artsc/libartsc.la +artscrec_SOURCES = artscrec.c + +artscmt_LDFLAGS = $(LDFLAGS) $(USE_THREADS) +artscmt_LDADD = $(top_builddir)/artsc/libartsc.la -lm $(LIBPTHREAD) $(LIBPOSIX4) +artscmt_SOURCES = artscmt.c + +playtofile_SOURCES = playtofile.cc playtofile_impl.cc playtofile_main.cc + +playtofile_LDADD = $(FLOWLIBS) \ + $(top_builddir)/soundserver/libsoundserver_idl.la \ + $(top_builddir)/soundserver/libkmedia2_idl.la + +catfile_SOURCES = catfile.cc + +catfile_LDADD = $(top_builddir)/soundserver/libkmedia2.la + +DISTCLEANFILES = hello.cc hello.h aggregation.cc aggregation.h \ + playtofile.cc playtofile.h + +####### Implicit rules + +####### Build rules + +helloclient.o: hello.h +hello.cc hello.h: $(top_srcdir)/examples/hello.idl $(MCOPIDL) + $(MCOPIDL) $(top_srcdir)/examples/hello.idl + +aggregation.cc aggregation.h: $(top_srcdir)/examples/aggregation.idl $(MCOPIDL) + $(MCOPIDL) $(top_srcdir)/examples/aggregation.idl + +playtofile.cc playtofile.h: $(srcdir)/playtofile.idl $(MCOPIDL) + $(MCOPIDL) -I$(top_srcdir)/flow $(srcdir)/playtofile.idl + diff --git a/examples/aggregation.idl b/examples/aggregation.idl new file mode 100644 index 0000000..3c02d31 --- /dev/null +++ b/examples/aggregation.idl @@ -0,0 +1,27 @@ +/* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +interface String { + attribute string value; + + void constructor(string value); +}; diff --git a/examples/artsccat.c b/examples/artsccat.c new file mode 100644 index 0000000..5f49f6f --- /dev/null +++ b/examples/artsccat.c @@ -0,0 +1,115 @@ + /* + + Copyright (C) 2001 Matthias Kretz + kretz@kde.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +/* + * This is another artscat written with aRts C API. It reads data from + * stdin, and plays it via the aRts soundserver. + * + * Compile programs using the aRts C API with + * + * cc -o artscdump artscdump.c `artsc-config --cflags` `artsc-config --libs` + * + * If you are using a makefile, it could look like this: + * + * CFLAGS=`artsc-config --cflags` + * LDFLAGS=`artsc-config --libs` + * + * artscdump: artscdump.c + */ +#include + +#include +#include +#include + +static void exitUsage(const char *progname) +{ + fprintf(stderr,"usage: %s [ options ] [ ]\n",progname); + fprintf(stderr,"-r set samplingrate to use\n"); + fprintf(stderr,"-b set number of bits (8 or 16)\n"); + fprintf(stderr,"-c set number of channels (1 or 2)\n"); + fprintf(stderr,"-h display this help and exit\n"); + exit(1); +} + +int main(int argc, char ** argv) +{ + int cfgSamplingRate = 44100; + int cfgBits = 16; + int cfgChannels = 2; + FILE *infile = stdin; + int pfd; + int packetsize; + char *buffer; + int size = 1024; + arts_stream_t stream; + int optch; + while((optch = getopt(argc,argv,"r:b:c:h")) > 0) + { + switch(optch) + { + case 'r': cfgSamplingRate = atoi(optarg); + break; + case 'b': cfgBits = atoi(optarg); + break; + case 'c': cfgChannels = atoi(optarg); + break; + case 'h': + default: + exitUsage(argc?argv[0]:"artsccat"); + break; + } + } + + if (optind < argc) + { + if(argv[optind] != "-") + { + infile = fopen(argv[optind],"w"); + if(!infile) + { + fprintf( stderr, "Can't open file '%s'.\n", argv[optind] ); + exit(1); + } + } + } + + pfd = fileno( infile ); + + arts_init(); + stream = arts_play_stream( cfgSamplingRate, cfgBits, cfgChannels, "artsccat" ); + packetsize = arts_stream_get( stream, ARTS_P_PACKET_SIZE ); + buffer = malloc(packetsize); + + do { + size = read( pfd, buffer, packetsize ); + size = arts_write( stream, buffer, size ); + } while( size > 0 ); + + arts_close_stream( stream ); + arts_free(); + + pclose( infile ); + free(buffer); + + return 0; +} diff --git a/examples/artscmt.c b/examples/artscmt.c new file mode 100644 index 0000000..bc9e98d --- /dev/null +++ b/examples/artscmt.c @@ -0,0 +1,143 @@ + /* + + Copyright (C) 2003 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +/* + * This is a threaded example using the aRts C API. + * + * Compile programs using the aRts C API with + * + * cc -o artscmt artscmt.c `artsc-config --cflags` `artsc-config --libs` + * + * If you are using a makefile, it could look like this: + * + * CFLAGS=`artsc-config --cflags` + * LDFLAGS=`artsc-config --libs` + * + * artscmt: artscmt.c + */ +#include +#include +#include +#include +#include +#include + +pthread_mutex_t arts_mutex; /* pthread mutex */ + +struct Writer +{ + pthread_t thread; + arts_stream_t stream; + float freq; +}; + +#define BUFFER_SIZE 1024 + +static void* writer(void *arg) +{ + struct Writer *self = arg; + int pos = 0; + + while(pos < 44100*10) + { + char buffer[BUFFER_SIZE], *to = buffer; + int i, written; + + for(i=0;ifreq)*15000.0); + pos++; + + /* put the samples in the packet */ + *to++ = sample & 0xff; + *to++ = (sample >> 8) & 0xff; + *to++ = sample & 0xff; + *to++ = (sample >> 8) & 0xff; + } + + written = 0; + do + { + int space; + + /* + * Since there is more than one thread, it is important not to keep the lock + * for a long time. We definitely don't want arts_write to block, while we + * keep the lock, to ensure that other threads can do something as well. So + * we check the available buffer space before writing to avoid blocking. + */ + pthread_mutex_lock(&arts_mutex); + space = arts_stream_get(self->stream, ARTS_P_BUFFER_SPACE); + if (space >= BUFFER_SIZE) + { + written = arts_write(self->stream, buffer, BUFFER_SIZE); + assert(written == BUFFER_SIZE); /* should handle errors here */ + } + pthread_mutex_unlock(&arts_mutex); + + /* + * If the buffer is full, wait some time to get free space again. The amout of + * time to wait needs to correspond to the buffer size we use for refilling. + */ + if (!written) + usleep(10000); /* 10ms */ + } while(!written); + } + return 0; +} + +int main() +{ + struct Writer writer1, writer2; + int error; + + error = arts_init(); + if(error < 0) + { + fprintf(stderr, "error initializing aRts driver: %s\n", arts_error_text(error)); + return 1; + } + + pthread_mutex_init(&arts_mutex, 0); + + writer1.stream = arts_play_stream(44100, 16, 2, "artscmt1"); + writer1.freq = 440; + pthread_create(&writer1.thread, NULL, writer, &writer1); + + writer2.stream = arts_play_stream(44100, 16, 2, "artscmt2"); + writer2.freq = 880; + pthread_create(&writer2.thread, NULL, writer, &writer2); + + pthread_join(writer1.thread, NULL); + pthread_join(writer2.thread, NULL); + + arts_close_stream(writer1.stream); + arts_close_stream(writer2.stream); + + pthread_mutex_destroy(&arts_mutex); + + arts_free(); + + return 0; +} diff --git a/examples/artscrec.c b/examples/artscrec.c new file mode 100644 index 0000000..80e91ae --- /dev/null +++ b/examples/artscrec.c @@ -0,0 +1,115 @@ + /* + + Copyright (C) 2001 Matthias Kretz + kretz@kde.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +/* + * This is another artsdump written with aRts C API. It reads data from + * the aRts soundserver and plays it via stdout. + * + * Compile programs using the aRts C API with + * + * cc -o artscdump artscdump.c `artsc-config --cflags` `artsc-config --libs` + * + * If you are using a makefile, it could look like this: + * + * CFLAGS=`artsc-config --cflags` + * LDFLAGS=`artsc-config --libs` + * + * artscdump: artscdump.c + */ +#include + +#include +#include +#include + +static void exitUsage(const char *progname) +{ + fprintf(stderr,"usage: %s [ options ] [ ]\n",progname); + fprintf(stderr,"-r set samplingrate to use\n"); + fprintf(stderr,"-b set number of bits (8 or 16)\n"); + fprintf(stderr,"-c set number of channels (1 or 2)\n"); + fprintf(stderr,"-h display this help and exit\n"); + exit(1); +} + +int main(int argc, char ** argv) +{ + int cfgSamplingRate = 44100; + int cfgBits = 16; + int cfgChannels = 2; + FILE *outfile = stdout; + int pfd; + int packetsize; + char *buffer; + int size; + arts_stream_t stream; + int optch; + while((optch = getopt(argc,argv,"r:b:c:h")) > 0) + { + switch(optch) + { + case 'r': cfgSamplingRate = atoi(optarg); + break; + case 'b': cfgBits = atoi(optarg); + break; + case 'c': cfgChannels = atoi(optarg); + break; + case 'h': + default: + exitUsage(argc?argv[0]:"artscdump"); + break; + } + } + + if (optind < argc) + { + if(argv[optind] != "-") + { + outfile = fopen(argv[optind],"w"); + if(!outfile) + { + fprintf( stderr, "Can't open file '%s'.\n", argv[optind] ); + exit(1); + } + } + } + + pfd = fileno( outfile ); + + arts_init(); + stream = arts_record_stream( cfgSamplingRate, cfgBits, cfgChannels, "artscdump" ); + packetsize = arts_stream_get( stream, ARTS_P_PACKET_SIZE ); + buffer = malloc(packetsize); + + do { + size = arts_read( stream, buffer, packetsize ); + size = write( pfd, buffer, size ); + } while( size > 0 ); + + arts_close_stream( stream ); + arts_free(); + + pclose( outfile ); + free(buffer); + + return 0; +} diff --git a/examples/artsctest.c b/examples/artsctest.c new file mode 100644 index 0000000..9eb5a9b --- /dev/null +++ b/examples/artsctest.c @@ -0,0 +1,72 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +/* + * This is another artscat written with aRts C API. It reads data from + * stdin, and plays it via the aRts soundserver. + * + * Compile programs using the aRts C API with + * + * cc -o artsctest artsctest.c `artsc-config --cflags` `artsc-config --libs` + * + * If you are using a makefile, it could look like this: + * + * CFLAGS=`artsc-config --cflags` + * LDFLAGS=`artsc-config --libs` + * + * artsctest: artsctest.c + */ + +#include +#include + +int main() +{ + arts_stream_t stream; + char buffer[8192]; + int bytes; + int errorcode; + + errorcode = arts_init(); + if(errorcode < 0) + { + fprintf(stderr,"arts_init error: %s\n", arts_error_text(errorcode)); + return 1; + } + + stream = arts_play_stream(44100,16,2,"artsctest"); + + while((bytes = fread(buffer,1,8192,stdin)) > 0) + { + errorcode = arts_write(stream,buffer,bytes); + if(errorcode < 0) + { + fprintf(stderr,"arts_write error: %s\n",arts_error_text(errorcode)); + return 1; + } + } + + arts_close_stream(stream); + arts_free(); + + return 0; +} diff --git a/examples/catfile.cc b/examples/catfile.cc new file mode 100644 index 0000000..2b34342 --- /dev/null +++ b/examples/catfile.cc @@ -0,0 +1,55 @@ +/* + + Copyright (C) 2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include +#include +#include + +using namespace std; +using namespace Arts; + +int main(int argc, char **argv) +{ + if(argc != 2) + { + fprintf(stderr, "usage: catfile \n"); + exit(1); + } + + Dispatcher dispatcher; + FileInputStream file; + StdoutWriter writer; + + if(!file.open(argv[1])) + { + printf("can't open file %s\n",argv[1]); + exit(1); + } + + connect(file, writer); + + file.start(); + writer.start(); + + while(!file.eof()) + dispatcher.ioManager()->processOneEvent(false); +} diff --git a/examples/dcasttest.cc b/examples/dcasttest.cc new file mode 100644 index 0000000..1d4127b --- /dev/null +++ b/examples/dcasttest.cc @@ -0,0 +1,72 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld stefan@space.twc.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include +#include +#include + +using namespace std; +using namespace Arts; + +/* + * This is a little test program that illustrates remote dynamic casting. + * Arts_SimpleSoundServer is a global object that is a SimpleSoundServer, + * so the first dynamic cast should succeed, while it is no Synth_PLAY, + * so the second dynamic cast should fail. + */ + +int main() +{ + Dispatcher dispatcher; + Object obj = Reference("global:Arts_SimpleSoundServer"); + + if(obj.isNull()) + { + cerr << "this test will only work if artsd is running" << endl; + exit(1); + } + + /* + * TODO: fix this. This fails currently as in the first line only an + * Object_stub will get created, no SimpleSoundServer_stub, and _cast + * which is used by DynamicCast wil only try to cast the _stub object, + * not do any further tricks. + */ + SimpleSoundServer server = DynamicCast(obj); + if(server.isNull()) + { + cerr << "remote dynamic casting is too restrictive" << endl; + exit(1); + } + + Synth_PLAY play = DynamicCast(obj); + if(!play.isNull()) + { + cerr << "remote dynamic casting doesn't do proper checks" << endl; + exit(1); + } + + cout << "remote dynamic casting seems to be fine" << endl; + return 0; +} diff --git a/examples/flow.cc b/examples/flow.cc new file mode 100644 index 0000000..116c21b --- /dev/null +++ b/examples/flow.cc @@ -0,0 +1,56 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld, stefan@space.twc.de + Nicolas Brodu, nicolas.brodu@free.fr + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "artsflow.h" +#include "connect.h" + +using namespace Arts; + +int main() +{ + Dispatcher dispatcher; + + // object creation + Synth_FREQUENCY freq; + Synth_WAVE_SIN sin; + Synth_PLAY play; + + // object initialization + setValue(freq, 440.0); + + // object connection + connect(freq, sin); + connect(sin, play, "invalue_left"); + connect(sin, play, "invalue_right"); + + // start all objects (maybe we should group objects like with QWidget + // parents and such?) + freq.start(); + sin.start(); + play.start(); + + // go + dispatcher.run(); +} diff --git a/examples/hello.idl b/examples/hello.idl new file mode 100644 index 0000000..8446500 --- /dev/null +++ b/examples/hello.idl @@ -0,0 +1,41 @@ +/* + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + Modified by Nicolas Brodu, nicolas.brodu@free.fr + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. +*/ + +// Test stuff: +interface HelloBase { + void hellobase(string s); +}; + +interface Hello : HelloBase { + /* + * counter like functionality (init, adding, getting total value) + */ + attribute long myValue; + void constructor(long i); + void add(long l); + void printTotal(); + + /* + * some hello world like stuff, string and number addition + */ + void hello(string s); + long sum(long a,long b); + string concat(string s1, string s2); +}; diff --git a/examples/hello_impl.cc b/examples/hello_impl.cc new file mode 100644 index 0000000..a3be704 --- /dev/null +++ b/examples/hello_impl.cc @@ -0,0 +1,76 @@ +/* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + Modified by Nicolas Brodu, nicolas.brodu@free.fr + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. +*/ + +#include "hello_impl.h" +#include + +using namespace std; + +void Hello_impl::hellobase(const string& s) +{ + printf("Hellobase '%s'!\n",s.c_str()); +} + +void Hello_impl::hello(const string& s) +{ + printf("Hello '%s'!\n",s.c_str()); +} + +void Hello_impl::constructor(long i) +{ + myvalue=i; +} + +long Hello_impl::myValue() +{ + return myvalue; +} + +void Hello_impl::myValue(long newValue) +{ + myvalue=newValue; +} + +void Hello_impl::add(long a) +{ + myvalue += a; +} + +void Hello_impl::printTotal() +{ + printf("Total=%ld\n",myvalue); +} + +long Hello_impl::sum(long a, long b) +{ + return a+b; +} + +string Hello_impl::concat(const string& s1, const string& s2) +{ + return s1+s2; +} + +REGISTER_IMPLEMENTATION(Hello_impl); diff --git a/examples/hello_impl.h b/examples/hello_impl.h new file mode 100644 index 0000000..484a890 --- /dev/null +++ b/examples/hello_impl.h @@ -0,0 +1,51 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + Modified by Nicolas Brodu, nicolas.brodu@free.fr + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#ifndef HELLO_IMPL_H +#define HELLO_IMPL_H + +#include "hello.h" + +using namespace std; + +class Hello_impl : virtual public Hello_skel { +private: + long myvalue; +public: + long myValue(); + void myValue(long newValue); + void constructor(long i); + void add(long increment); + void printTotal(); + + void hello(const string& s); + long sum(long a, long b); + string concat(const string& s1, const string& s2); + + void hellobase(const string& s); +}; + +#endif /* HELLO_IMPL_H */ diff --git a/examples/helloclient.cc b/examples/helloclient.cc new file mode 100644 index 0000000..c7d3022 --- /dev/null +++ b/examples/helloclient.cc @@ -0,0 +1,76 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "hello.h" + +#include +#include + +using namespace Arts; + +int main(int argc, char **argv) +{ + if(argc != 2) + { + fprintf(stderr,"usage: %s \n",argv[0]); + exit(1); + } + + Dispatcher dispatcher; + + Hello h = Reference(argv[1]); + if(h.isNull()) + { + fprintf(stderr,"can't connect to the object\n"); + exit(1); + } + + const char *who = getenv("LOGNAME"); + if(!who) who = "stefan"; + + printf("calling h.hello(\"%s\")\n", who); + h.hello(who); +/* + printf("h->sum(2,4) is %ld\n", + h->sum2(2,4)); + + printf("h->sum(2,4,6) is %ld\n", + h->sum3(2,4,6)); +*/ + h.myValue(6); + printf("h.myValue(6), h.myValue() is %ld\n", + h.myValue()); + + printf("h.concat(\"MCOP \",\"is great!\") is \"%s\"\n", + h.concat("MCOP ","is great!").c_str()); + + /* + int i,j = 0; + for(i=0;i<100000;i++) + j += h->sum2(2,4); + printf("%d\n",j); + */ + return 0; +} diff --git a/examples/hellodynamic.cc b/examples/hellodynamic.cc new file mode 100644 index 0000000..5dabec0 --- /dev/null +++ b/examples/hellodynamic.cc @@ -0,0 +1,94 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "hello.h" +#include "dynamicrequest.h" + +#include +#include +#include + +using namespace std; +using namespace Arts; + +/* + * Hellodynamic illustrates the usage of the DynamicRequest class to perform + * dynamic requests. There are two things you can try + * + * hellodynamic + * + * which will use a local implementation of a hello object, and + * + * hellodynamic + * + * which will use a remote implementation of a hello object. + */ +int main(int argc, char **argv) +{ + Dispatcher dispatcher; + Hello h; + + // Check if we should connect to a remote server: + if(argc == 2) + { + h = Reference(argv[1]); + if(h.isNull()) + { + fprintf(stderr,"can't connect to the object\n"); + exit(1); + } + } + + // find out logname + const char *who = getenv("LOGNAME"); + if(!who) who = "stefan"; + + printf("calling h.hello(\"%s\")\n", who); + + // the dynamic equivalent to h.hello(who) + DynamicRequest hellorequest(h); + + if(!hellorequest.method("hello").param(who).invoke()) + cout << "dynamic invocation to h.hello(...) failed" << endl; + + /* + Note: you could reuse hellorequest here, and indeed, if you + call the _same_ method over and over again, you'll get quite + some speed gain as the signature is only looked up once. + */ + + // set a value (no error checking here, I am lazy ;) + DynamicRequest(h).method("_set_myValue").param(42).invoke(); + + // get a value via "normal" interface + printf("h.myValue() is %ld (after setting it to 42)\n", h.myValue()); + + // call h.concat("MCOP ","rules.") dynamically + string s; + DynamicRequest(h).method("concat").param("MCOP ").param("rules.").invoke(s); + cout << "Conclusion of this test: " << s << endl; + + return 0; +} diff --git a/examples/hellodynamic2.cc b/examples/hellodynamic2.cc new file mode 100644 index 0000000..8f8a1e0 --- /dev/null +++ b/examples/hellodynamic2.cc @@ -0,0 +1,124 @@ + /* + + Copyright (C) 2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "hello.h" +#include "dynamicskeleton.h" +#include "debug.h" +#include "stdio.h" + +using namespace Arts; +using namespace std; + +namespace Arts { typedef DynamicSkeleton Object_dskel; } + +class HelloDynamic : public Arts::Object_dskel { +protected: + long myValue; + +public: + HelloDynamic() : Arts::Object_dskel("Hello") { + } + void process(long methodID, Arts::Buffer *request, Arts::Buffer *result) + { + const Arts::MethodDef& methodDef = getMethodDef(methodID); + + if(methodDef.name == "hello") // void hello(string); + { + string s; request->readString(s); + printf("Hello '%s'!\n",s.c_str()); + } + else if(methodDef.name == "_set_myValue") // attribute long myValue; + { + myValue = request->readLong(); + } + else if(methodDef.name == "_get_myValue") + { + result->writeLong(myValue); + } + else if(methodDef.name == "concat") + { + string s1; request->readString(s1); + string s2; request->readString(s2); + result->writeString(s1+s2); + } + else if(methodDef.name == "sum") + { + long a = request->readLong(); + long b = request->readLong(); + result->writeLong(a+b); + } + else + { + arts_fatal("method %s unimplemented", methodDef.name.c_str()); + } + } +}; + +/* + * this program illustrates that you /can/ implement an interface without + * using the IDL compiler skeleton do to so - this is useful if you want + * to create a language or object system binding, where you don't know + * all interfaces that are present at compile time + * + * however, it's definitely advanced stuff, and not for daily use ;) + */ +int main() +{ + Dispatcher dispatcher; + + Object obj = Object::_from_base(new HelloDynamic()); + if(obj.isNull()) + arts_fatal("dimpl is no object?"); + + HelloBase b = DynamicCast(obj); + if(b.isNull()) + arts_fatal("can't cast the object to HelloBase"); + + + Hello h = DynamicCast(obj); + /*arts_info("%d",obj.isCompatibleWith("Hello"));*/ + + if(h.isNull()) + arts_fatal("can't destringify to the object"); + + const char *who = getenv("LOGNAME"); + if(!who) who = "stefan"; + + arts_info("calling h.hello(\"%s\")", who); + h.hello(who); + + h.myValue(6); + arts_info("h.myValue(6), h.myValue() is %ld", + h.myValue()); + + arts_info("h.concat(\"MCOP \",\"is great!\") is \"%s\"", + h.concat("MCOP ","is great!").c_str()); + + /* + int i,j = 0; + for(i=0;i<100000;i++) + j += h.sum(2,4); + printf("%d\n",j); + */ + + return 0; +} diff --git a/examples/hellomain.cc b/examples/hellomain.cc new file mode 100644 index 0000000..f194456 --- /dev/null +++ b/examples/hellomain.cc @@ -0,0 +1,77 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld stefan@space.twc.de + Nicolas Brodu, brodu@kde.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "hello.h" +#include + +using namespace std; +using namespace Arts; + +int main() +{ + Dispatcher dispatcher; + + // Just use plain C++! + Hello server; + server.hello("server"); + + // creation from MCOP reference + Hello client( Reference( server.toString() ) ); + if (!client.isNull()) client.hello("local test"); + else cout << "fatal: a valid reference can't be decoded" << endl; + + // creation from wrong reference + Hello xclient( Reference("fdshjkhdsf") ); + + // check result => should be null + if (xclient.isNull()) cout << "passed invalid reference test" << endl; + else cout << "fatal: an invalid reference can be decoded" << endl; + + // using a constructor + Hello hint(3); + cout << hint.myValue() << endl; + + + Hello castsrc; + HelloBase casthint = castsrc; + casthint.hellobase("cast test passed"); + if(castsrc.isNull()) cout << "cast problem with auto creation" << endl; + castsrc.hello("second cast test passed"); + + // Can copy (or here copy constructor) the objects + Hello hcopy = hint; + hcopy.add(5); + hcopy.printTotal(); + + // dynamic creation is OK + Hello* dyn = new Hello; + cout << dyn->concat("I am"," a dynamic hello") << endl; + dyn->hellobase("dynamic hellobase hello"); + delete dyn; + +// dispatcher.run(); + return 0; + +} diff --git a/examples/helloserver.cc b/examples/helloserver.cc new file mode 100644 index 0000000..2e37de5 --- /dev/null +++ b/examples/helloserver.cc @@ -0,0 +1,52 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "common.h" +#include "hello_impl.h" + +#include +#include +#include + +using namespace std; +using namespace Arts; + +int main() +{ + Dispatcher dispatcher(0,Dispatcher::startUnixServer); + Hello server; + + string reference = server.toString(); + printf("%s\n",reference.c_str()); + + Hello h = Reference(reference); + if(!h.isNull()) + h.hello("local test"); + else + printf("Local access to the Hello_impl object failed?\n"); + + dispatcher.run(); + return 0; +} diff --git a/examples/irdemo.cc b/examples/irdemo.cc new file mode 100644 index 0000000..4345235 --- /dev/null +++ b/examples/irdemo.cc @@ -0,0 +1,155 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "common.h" + +#include +#include +#include +#include + +using namespace std; +using namespace Arts; + +static void printInterface(InterfaceDef id) +{ + string inherit; + if(id.inheritedInterfaces.size()) + { + vector::iterator ii; + bool first = true; + inherit = ": "; + for(ii = id.inheritedInterfaces.begin(); ii != id.inheritedInterfaces.end(); ii++) + { + if(!first) inherit +=","; + first = false; + inherit += (*ii)+" "; + } + } + printf("interface %s %s{\n",id.name.c_str(),inherit.c_str()); + // attributes, streams + vector::iterator ai; + for(ai = id.attributes.begin(); ai != id.attributes.end(); ai++) + { + const AttributeDef& ad = *ai; + if(ad.flags & attributeAttribute) + { + /* readwrite */ + if(ad.flags & (streamOut|streamIn) == (streamOut|streamIn)) + { + printf(" attribute %s %s;\n",ad.type.c_str(), ad.name.c_str()); + } + else + { + if(ad.flags & streamOut) /* readable from outside */ + { + printf(" readonly attribute %s %s;\n", + ad.type.c_str(), ad.name.c_str()); + } + if(ad.flags & streamIn) /* writeable from outside */ + { + printf(" ?writeonly? attribute %s %s;\n", + ad.type.c_str(), ad.name.c_str()); + } + } + } + if(ad.flags & attributeStream) + { + const char *dir = (ad.flags & streamOut)?"out":"in"; + const char *async = (ad.flags & streamAsync)?"async ":""; + string type = ad.type; + if(type == "float" && !(ad.flags & streamAsync)) type = "audio"; + + printf(" %s%s %s stream %s;\n",async,dir, + type.c_str(),ad.name.c_str()); + } + } + + // methods + vector::iterator mi; + for(mi = id.methods.begin();mi != id.methods.end(); mi++) + { + MethodDef& md = *mi; + printf(" %s %s(",md.type.c_str(),md.name.c_str()); + + bool first = true; + vector::iterator pi; + for(pi = md.signature.begin(); pi != md.signature.end(); pi++) + { + ParamDef& pd = *pi; + if(!first) printf(", "); + printf("%s %s",pd.type.c_str(),pd.name.c_str()); + first = false; + } + printf(");\n"); + } + printf("}\n"); +} + +/* + * This demo shows that you can find out what interface an object has and + * what types it needs to work without knowing anything but the object + * reference. + * + * The reason for that is that every object offers the _interfaceName + * _queryInterface and _queryType methods, which you can use to find out + * anything you need to know to talk to that object. + * + * Just pass this programm an MCOP object reference, and it will print out + * the corresponding interface. + * + * (TODO: one could make it print out all inherited interfaces and the + * types that are used in the interface, too. Ports, etc could be shown + * as well). + */ + +/** + * Interface repository demo - reasonable testcase: + * + * - make sure artsd is running + * - irdemo global:Arts_SimpleSoundServer + */ +int main(int argc, char **argv) +{ + if(argc != 2) + { + fprintf(stderr,"usage: %s \n",argv[0]); + exit(1); + } + + Dispatcher dispatcher; + Object o = Reference(argv[1]); + if(o.isNull()) + { + fprintf(stderr,"can't connect to the object\n"); + exit(1); + } + + string iname = o._interfaceName(); + InterfaceDef idef = o._queryInterface(iname); + printInterface(idef); + + return 0; +} diff --git a/examples/playtofile.idl b/examples/playtofile.idl new file mode 100644 index 0000000..6aa341e --- /dev/null +++ b/examples/playtofile.idl @@ -0,0 +1,41 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +/* + * this is an example interface which dumps things to a file + */ +#include + +module Arts { + interface PlayToFile : SynthModule { + /** + * filename, - = default = stdout + */ + attribute string filename; + + /** + * write more data to file ;) + */ + void goOn(); + default in audio stream left, right; + }; +}; diff --git a/examples/playtofile_impl.cc b/examples/playtofile_impl.cc new file mode 100644 index 0000000..63a5708 --- /dev/null +++ b/examples/playtofile_impl.cc @@ -0,0 +1,99 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "playtofile.h" +#include "flowsystem.h" +#include "stdsynthmodule.h" +#include "convert.h" +#include "stdio.h" + +using namespace Arts; +using namespace std; + +namespace Arts { + class PlayToFile_impl : virtual public PlayToFile_skel, + virtual public StdSynthModule + { + typedef unsigned char uchar; + unsigned char *outblock; + unsigned long maxsamples; + string _filename; + FILE *out; + public: + PlayToFile_impl() : _filename("-") + { + } + void filename(const string& newfilename) { + _filename = newfilename; + filename_changed(_filename); + } + + string filename() { return _filename; } + + void streamInit() { + maxsamples = 0; + outblock = 0; + if(_filename == "-") + out = stdout; + else + out = fopen(_filename.c_str(),"w"); + } + void streamEnd() { + if(outblock) + { + delete[] outblock; + outblock = 0; + } + if(out != stdout) + { + fclose(out); + } + } + + void calculateBlock(unsigned long samples) + { + if(samples > maxsamples) + { + maxsamples = samples; + + if(outblock) delete[] outblock; + outblock = new uchar[maxsamples * 4]; // 2 channels, 16 bit + } + + convert_stereo_2float_i16le(samples,left,right, outblock); + fwrite(outblock, 1, 4 * samples,out); + } + + /* + * this is the most tricky part here - since we will run in a context + * where no audio hardware will play the "give me more data role", + * we'll have to request things ourselves (requireFlow() tells the + * flowsystem that more signal flow should happen, so that + * calculateBlock will get called + */ + void goOn() + { + _node()->requireFlow(); + } + }; + REGISTER_IMPLEMENTATION(PlayToFile_impl); +}; diff --git a/examples/playtofile_main.cc b/examples/playtofile_main.cc new file mode 100644 index 0000000..c7f85fd --- /dev/null +++ b/examples/playtofile_main.cc @@ -0,0 +1,147 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "playtofile.h" +#include "kmedia2.h" +#include "debug.h" +#include "dynamicrequest.h" +#include "connect.h" +#include "flowsystem.h" +#include +#include + +using namespace Arts; +using namespace std; + +/* copypasted from simplesoundserver_impl.cc */ +PlayObject createPlayObject(const string& filename) +{ + string objectType = ""; + + /* + * figure out extension (as lowercased letters) + */ + string extension = ""; + bool extensionok = false; + string::const_reverse_iterator i; + for(i = filename.rbegin(); i != filename.rend() && !extensionok; i++) + { + if(*i == '.') + extensionok = true; + else + extension = (char)tolower(*i) + extension; + } + + /* + * query trader for PlayObjects which support this + */ + if(extensionok) + { + arts_debug("search playobject, extension = %s",extension.c_str()); + + TraderQuery query; + query.supports("Interface","Arts::PlayObject"); + query.supports("Extension",extension); + + vector *offers = query.query(); + if(!offers->empty()) + objectType = offers->front().interfaceName(); // first offer + + delete offers; + } + + /* + * create a PlayObject and connect it + */ + if(!objectType.empty()) + { + arts_debug("creating %s to play file", objectType.c_str()); + + PlayObject result = SubClass(objectType); + if(result.loadMedia(filename)) + { + result._node()->start(); + return result; + } + else arts_warning("couldn't load file %s", filename.c_str()); + } + else arts_warning("file format extension %s unsupported",extension.c_str()); + + return PlayObject::null(); +} + +/* + * This is an example for dumping things to a file. It demonstates, that + * + * a) you can use all aRts objects in a non-realtime environment (i.e. + * the time in the PlayObject will pass much faster than the outside + * time when dumping things to a file) + * + * b) complayObjectnents will be dynamically loaded as needed + * + * c) you need to do small tricks to get the signal flow going when you are + * not having audio modules around + * + * d) by implementing aRts modules, you can easily grab and insert data from/to + * arbitary non-aRts sources - for instance, a wave editor might implement + * own modules to get the wave from/to memory + */ +int main(int argc, char **argv) +{ + Dispatcher d; + + if(argc != 2 && argc != 3) + { + cerr << "usage: playtofile [ ]" << endl; + exit(1); + } + PlayObject playObject = createPlayObject(argv[1]); + if(playObject.isNull()) + { + cerr << "can't read inputfile " << argv[1] << endl; + exit(1); + } + + playObject.play(); + + PlayToFile playToFile; + if(argc == 3) playToFile.filename(argv[2]); + + connect(playObject, "left", playToFile,"left"); + connect(playObject, "right", playToFile,"right"); + + // + // special case when using mpeglib, do tell it not to block (internal + // interface) - we also put an usleep here to ensure that the threads + // and everything is fully initialized as soon as we start + usleep(100000); + if(playObject._base()->_isCompatibleWith("DecoderBaseObject")) + if(!DynamicRequest(playObject).method("_set_blocking").param(true).invoke()) + cerr << "mpeglib, and blocking attribute can't be changed?" << endl; + // + + playToFile.start(); + while(playObject.state() != posIdle) + playToFile.goOn(); + + return 0; +} diff --git a/examples/referenceinfo.cc b/examples/referenceinfo.cc new file mode 100644 index 0000000..d73776c --- /dev/null +++ b/examples/referenceinfo.cc @@ -0,0 +1,57 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "common.h" +#include + +using namespace Arts; + +int main(int argc, char **argv) +{ + Dispatcher dispatcher; + ObjectReference r; + + if(argc != 2) + { + fprintf(stderr,"usage: %s \n",argv[0]); + exit(1); + } + + if(!dispatcher.stringToObjectReference(r,argv[1])) + { + fprintf(stderr, + "Can't read this object reference (invalid?)\n"); + exit(1); + } + printf("serverID: %s\n",r.serverID.c_str()); + printf("objectID: %ld\n\n",r.objectID); + + printf("URLs:\n"); + std::vector::iterator ui; + for(ui = r.urls.begin(); ui != r.urls.end();ui++) + printf(" - %s\n",ui->c_str()); + + return 0; +} diff --git a/examples/streamsound.cc b/examples/streamsound.cc new file mode 100644 index 0000000..a19bd27 --- /dev/null +++ b/examples/streamsound.cc @@ -0,0 +1,106 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "soundserver.h" +#include "stdsynthmodule.h" + +#include +#include +#include +#include +#include + +using namespace std; +using namespace Arts; + +class Sender : public ByteSoundProducer_skel, + public StdSynthModule +{ + bool _finished; + int pos; +public: + Sender() : _finished(false), pos(0) + { + } + long samplingRate() { return 44100; } + long channels() { return 2; } + long bits() { return 16; } + bool finished() { return _finished; } + + static const int packetCount = 10, packetCapacity = 1024; + void streamStart() + { + /* + * start streaming + */ + outdata.setPull(packetCount, packetCapacity); + } + + void request_outdata(DataPacket *packet) + { + /* + * fill the packet with new data + */ + // ----------------- audio fill up start ----------------- + + int j; + mcopbyte *to = &packet->contents[0]; + for(j=0;j> 8) & 0xff; + *to++ = right & 0xff; + *to++ = (right >> 8) & 0xff; + } + + // ------------------ audio fill up end ------------------ + packet->send(); + } +}; + +int main(int argc, char **argv) +{ + Dispatcher dispatcher; + SimpleSoundServer server = Reference("global:Arts_SimpleSoundServer"); + + if(server.isNull()) + { + cerr << "Can't connect to sound server" << endl; + return 1; + } + + ByteSoundProducer sender = ByteSoundProducer::_from_base(new Sender()); + server.attach(sender); + sender.start(); + dispatcher.run(); + server.detach(sender); // in this example: not reached +} diff --git a/examples/testaggregation.cc b/examples/testaggregation.cc new file mode 100644 index 0000000..76c2773 --- /dev/null +++ b/examples/testaggregation.cc @@ -0,0 +1,73 @@ +/* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include "aggregation.h" +#include + +using namespace std; +using namespace Arts; + +class String_impl : virtual public String_skel { + string _value; +public: + void constructor(const std::string& value) { _value = value; } + string value() { return _value; } + void value(const std::string& newValue) { _value = newValue; } +}; + +REGISTER_IMPLEMENTATION(String_impl); + +void printall(Arts::Object o, std::string pre = "") +{ + String s; + s = DynamicCast(o); + if(!s.isNull()) + cout << pre << " - " << s.value() << endl; + + vector *children = s._queryChildren(); + vector::iterator i; + for(i = children->begin(); i != children->end(); i++) + printall(s._getChild(*i), pre+" "); +} + +/* + * Small test case for aggregation + * + * The idea behind all this is that you can add children to objects, building + * a tree (or if you like graph) of objects without the objects knowing anything + * about this. Aggregation has strong references, that means, the objects you + * add together in a tree will stay this way, as long as you keep a reference + * to the root. + */ +int main() +{ + Dispatcher d; + + String s("spreadsheet"); + s._addChild(String("chart"),"child1"); + s._addChild(String("image"),"child2"); + printall(s); + + cout << "deleting \"child1\"" << endl; + if(!s._removeChild("child1")) cout << "FAIL" << endl; + printall(s); +} diff --git a/examples/testasubsys.cc b/examples/testasubsys.cc new file mode 100644 index 0000000..e0480ed --- /dev/null +++ b/examples/testasubsys.cc @@ -0,0 +1,142 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include +#include +#include "audiosubsys.h" +#include "convert.h" +#include "dispatcher.h" + +using namespace std; +using namespace Arts; + +class SinTest : public ASProducer { +protected: + int audiofd; + int done; + AudioSubSystem *as; + bool attached; + +public: + SinTest(); + virtual ~SinTest(); + void needMore(); + void run(long samples); +}; + +SinTest::SinTest() : done(0), as(AudioSubSystem::the()) +{ + // initialize and open audio subsystem (defaults to 44kHz, 16bit, stereo) + attached = as->attachProducer(this); + if(!attached) + { + cout << "audio subsystem is already used?" << endl; + } + else + { + if(as->open() == false) + { + cout << "audio subsystem init failed (" + << as->error() << ")" << endl; + audiofd = -1; + } + else + audiofd = as->selectWriteFD(); + } +} + +SinTest::~SinTest() +{ + // deinitialize the audio subsystem + if(attached) + as->detachProducer(); +} + +void SinTest::run(long samples) +{ + // run this loop until enough samples are produced + while(attached && audiofd >= 0 && (done < samples)) + { + fd_set wfds, efds; + FD_ZERO(&wfds); + FD_ZERO(&efds); + FD_SET(audiofd, &wfds); + FD_SET(audiofd, &efds); + + // look if the audio filedescriptor becomes writeable + int result = select(audiofd+1,0,&wfds,&efds,0); + if(result > 0) + { + // if yes, tell the audio subsystem to do something about it + if(FD_ISSET(audiofd, &wfds)) + as->handleIO(AudioSubSystem::ioWrite); + if(FD_ISSET(audiofd, &efds)) + as->handleIO(AudioSubSystem::ioExcept); + } + else + { + cout << "select returned " << result << endl; + } + } +} + +/* + * needMore is a callback by the audio subsystem, which is made as soon as + * the internal buffers need a refill + */ +void SinTest::needMore() +{ + float left[100], right[100]; + unsigned char out[400]; + + // generate two waves, one 440 Hz (left), one 880Hz (right) + for(int i=0;i<100;i++) + { + left[i] = sin((float)i*6.28/100.0); + right[i] = sin((float)i*6.28/50.0); + } + convert_stereo_2float_i16le(100, left, right, out); + + // write them to the audio subsystem + as->write(out,400); + done += 100; +} + +/* + * This is intended to help testing the audio subsystem with different + * hardware without needing to use the whole server. + * + * Warning: this is *not* an example how to use aRts (there are others), + * but a simple test program for debugging purposes. + */ +int main() +{ + Dispatcher d; // to get startup classes executed + + // the test, generate 88100 samples (2 seconds) of pure sine wave test data + SinTest s; + s.run(88100); + return 0; +} diff --git a/examples/testdhandle.cc b/examples/testdhandle.cc new file mode 100644 index 0000000..a42ad46 --- /dev/null +++ b/examples/testdhandle.cc @@ -0,0 +1,115 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "gslpp/datahandle.h" +#include "soundserver.h" +#include "stdsynthmodule.h" +#include "artsflow.h" +#include "connect.h" + +#include +#include +#include +#include +#include + +using namespace std; +using namespace Arts; + +int main(int argc, char **argv) +{ + if(argc<2) + { + cerr << "USAGE: " << argv[0] << " [filename]\n"; + exit(1); + } + + Dispatcher dispatcher; + SoundServer server = Reference("global:Arts_SoundServer"); + + cout << "opening '" << argv[1] << "' locally...\n"; + + GSL::WaveFileInfo info(argv[1]); + if(info.error()) + { + cerr << "GSL error " << info.error() << + " (" << gsl_strerror(info.error()) << ") while loading info.\n"; + exit(1); + } + cout << "file contains " << info.waveCount() << " waves:\n"; + for(int i=0; i +#include +#include +#include "dispatcher.h" +#include "thread.h" + +using namespace Arts; +using namespace std; + +class Counter : public Arts::Thread +{ + string name; +public: + Counter(const string& name) :name(name) {} + + void run() { + for(int i = 0;i < 10;i++) + { + printf("[%s] %d\n",name.c_str(),i+1); + sleep(1); + } + printf("[%s] terminating.\n", static_cast + (SystemThreads::the()->getCurrentThread())->name.c_str()); + } +}; + +int main() +{ + Dispatcher dispatcher; + Counter c1("counter1"), c2("counter2"); + + if(SystemThreads::supported()) + printf("We have a system threads (counters should count parallel).\n"); + else + printf("No system threads (counters will not count parallel).\n"); + + c1.start(); + c2.start(); + c1.waitDone(); + c2.waitDone(); + return 0; +} diff --git a/examples/x11commtest.cc b/examples/x11commtest.cc new file mode 100644 index 0000000..fa793b4 --- /dev/null +++ b/examples/x11commtest.cc @@ -0,0 +1,76 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + Modified by Nicolas Brodu, brodu@kde.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include +#include "common.h" + +using namespace std; +using namespace Arts; + +/* + * Test program for X11GlobalComm (communication over X11 root window + * properties), and since X11GlobalComm is an dynamically extension, + * extension loading is tested as well. + */ +int main(int argc, char **argv) +{ + Dispatcher dispatcher; + GlobalComm gcomm( SubClass("Arts::X11GlobalComm") ); + + if (gcomm.isNull()) { + cerr << "Cannot create a X11GlobalComm object" << endl; + return 2; + } + + if(argc == 4) + { + if(string(argv[1]) == "put") + { + gcomm.put(argv[2],argv[3]); + return 0; + } + } + if(argc == 3) + { + if(string(argv[1]) == "get") + { + cout << gcomm.get(argv[2]) << endl; + return 0; + } + if(string(argv[1]) == "erase") + { + gcomm.erase(argv[2]); + return 0; + } + } + + cerr << "This is a test for the X11GlobalComm class. Use" << endl << endl + << " " << argv[0] << " put " << endl + << " " << argv[0] << " get " << endl + << " " << argv[0] << " erase " << endl << endl + << "to test the communication via X11 RootWindow properties." << endl; + return 1; +} diff --git a/flow/Makefile.am b/flow/Makefile.am new file mode 100644 index 0000000..720ca47 --- /dev/null +++ b/flow/Makefile.am @@ -0,0 +1,49 @@ + +SUBDIRS = mcopclass gsl gslpp +INCLUDES = -I$(top_srcdir)/mcop -I$(top_builddir)/mcop $(all_includes) +AM_CXXFLAGS = $(MAS_CFLAGS) $(JACK_CFLAGS) -DQT_CLEAN_NAMESPACE + +####### Files + +lib_LTLIBRARIES = libartsflow_idl.la libartsflow.la + +libartsflow_idl_la_SOURCES = artsflow.cc +libartsflow_idl_la_LDFLAGS = -no-undefined -version-info 1:0 $(all_libraries) +libartsflow_idl_la_LIBADD = $(top_builddir)/mcop/libmcop.la $(LIBPOSIX4) + +libartsflow_la_LIBADD = $(top_builddir)/mcop/libmcop.la libartsflow_idl.la $(top_builddir)/flow/gslpp/libgslpp.la $(LIBAUDIOFILE) $(LIBASOUND) $(LIBAUDIOIO) $(LIBOSSAUDIO) $(LIBAUDIONAS) $(LIBCSL) $(SGILIBAUDIO) $(LIBESD) $(LIBMAS) $(JACK_LIBADD) -lm \ + $(top_builddir)/flow/gsl/libgsl.la +libartsflow_la_LDFLAGS = $(MAS_LDFLAGS) $(JACK_LDFLAGS) $(LIBAUDIOFILE_LDFLAGS) $(LIBAUDIONAS_LDFLAGS) $(LIBESD_LDFLAGS) -no-undefined -version-info 1:0 +libartsflow_la_COMPILE_FIRST = artsflow.h +libartsflow_la_SOURCES = synth_play_impl.cc \ + gslschedule.cc audiosubsys.cc \ + pipebuffer.cc convert.cc synth_wave_sin_impl.cc synth_frequency_impl.cc \ + synth_multi_add_impl.cc synth_add_impl.cc synth_mul_impl.cc \ + synth_play_wav_impl.cc stdsynthmodule.cc cache.cc asyncschedule.cc \ + bytestreamtoaudio_impl.cc stereovolumecontrol_impl.cc \ + stereoeffectstack_impl.cc fft.c stereofftscope_impl.cc virtualports.cc \ + bus.cc audiomanager_impl.cc synth_record_impl.cc resample.cc \ + audioio.cc audioiooss.cc audioioalsa.cc audioioalsa9.cc \ + audioionull.cc audioiolibaudioio.cc audioioesd.cc audioiojack.cc \ + audioiosun.cc audioioaix.cc audioionas.cc cpuinfo.cc \ + audioioossthreaded.cc audiotobytestream_impl.cc audioiosgi.cc \ + audioiocsl.cc audioiomas.cc datahandle_impl.cc + +artsincludedir = $(includedir)/arts +artsinclude_HEADERS = artsflow.h audiosubsys.h cache.h \ + cachedwav.h convert.h pipebuffer.h stdsynthmodule.h \ + synthschedule.h fft.h artsflow.idl audioio.h resample.h \ + cpuinfo.h bufferqueue.h gslschedule.h + +DISTCLEANFILES = artsflow.cc artsflow.h artsflow.mcoptype artsflow.mcopclass + +artsflow.cc artsflow.h: $(top_srcdir)/flow/artsflow.idl $(MCOPIDL) + $(MCOPIDL) -t $(top_srcdir)/flow/artsflow.idl + +artsflow.mcoptype: artsflow.h +artsflow.mcopclass: artsflow.h + +######## install idl typeinfo files + +mcoptypedir = $(libdir)/mcop +mcoptype_DATA = artsflow.mcoptype artsflow.mcopclass diff --git a/flow/artsflow.idl b/flow/artsflow.idl new file mode 100644 index 0000000..44424e0 --- /dev/null +++ b/flow/artsflow.idl @@ -0,0 +1,566 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +/* + * arts.idl - MCOP port. What's missing currently in MCOP? + * + * - namespaces (module) + */ + +module Arts { // analog real time synthesizer + +enum AutoSuspendState { asNoSuspend, asSuspend, asSuspendStop, asSuspendMask = 0x3, + asProducer = 0x10, asConsumer = 0x20, asDirectionMask = 0x30 }; + +/** + * The SynthModule interface is the base for all modules containing streams. + * + * There are two goals achieved by this interface. On one side, there is + * functionality which users of stream carrying modules want to use (which + * is: start streaming, stop streaming). + * + * On the other hand, there is functionality which the flow system will use + * to achieve these goals. + */ +interface SynthModule { + // interface for users of this module + + /** + * This function starts the streaming (e.g. the module will start + * producing samples) - if you write a module, do not reimplement this, + * instead reimplement streamInit/streamStart + */ + void start(); + + /** + * This function stops the streaming - if you write a plugin, do not + * reimplement this, instead reimplement streamEnd + */ + void stop(); + + // interface for people implementing modules + + /** + * this is supposed to be the initialization every module passes after + * all attributes have been set up (e.g. you can see which file to open, + * how to initialize your filter coefficients or whatever) + */ + void streamInit(); + + /** + * starts the I/O of the module + */ + void streamStart(); + + /** + * stop the thing again, and free data possibly allocated in streamInit + */ + void streamEnd(); + + /** + * If you run a mixer desk (without anything connected), no calculations + * need to be done - since the output is silent anyway. For this reason, + * there exists this autosuspend attribute. It allows the flow system + * to detect the idle condition, and start suspending the calculations, + * until something "important" happens again. + * + * There are three possible values: + * + * @li asNoSuspend - this one is appropriate when you have a module that + * is active by itself + * @li asSuspend - this one is appropriate for modules that "do nothing" + * by themselves + * @li asSuspendStop - this one is for modules that should be stopped, when + * the system gets suspended, and restarted when the + * system will start again - an example for this is + * soundcard output + * + * A module should choose asSuspend (or asSuspendStop) only if the + * following conditions are true: + * + * @li given constant inputs (like 3.0 on all ports), the module will + * give constant output after some time + * @li given only 0.0 inputs, the module will give only 0.0 outputs + * after some time + * @li the module does not synchronize itself through signal flow (i.e. + * a midi sequence which "knows" when a second has passed through + * the signal flow breaks when suspension happens) + * @li the module can't be brought to do something with a method + * invocation (i.e. a module which starts generating noise for + * a second whenever the noise() method is called is not suspendable) + * @li the module has no internal state that changes over time when only + * constant inputs are given + * + * Typical examples for suspendable modules are arithmetic operations, + * filters, delay/hall/reverb. + * + * Typical examples for non-suspendable modules are sequences, midi stuff, + * oscillators, sample players,... + * + * To deal with modules which either input data from some external source + * (i.e. soundcard input) or output data to some external destination, + * (i.e. soundcard output) the following flags are available: + * + * @li asProducer - set this flag for modules which fulfill the conditions + * for a suspendable module, but produce non-zero output + * even when left alone + * @li asConsumer - set this flag for modules which write the data to + * some external destination - that is - definitely + * require constant input to be suspended + * + * The suspension algorithm will first divide the graph of modules into + * subgraphs of interconnected modules. A subgraph is suspendable if + * all of its modules are suspendable and the subgraph does not contain + * producer(s) and consumer(s) at the same time. + * + * Finally, our module graph is suspendable if all its subgraphs are. + */ + readonly attribute AutoSuspendState autoSuspend; +}; + +/** + * Plays a stream of audio data to the soundcard + */ +interface Synth_PLAY : SynthModule { + // attribute string channels; + default in audio stream invalue_left,invalue_right; +}; + +/** + * Records a stream of audio data from the soundcard + */ +interface Synth_RECORD : SynthModule { + // attribute string channels; + default out audio stream left,right; +}; + +/** + * A frequency generator + * + * This kind of object is used to create frequencies. Oscillators are connected + * at the output of this object + */ +interface Synth_FREQUENCY : SynthModule { + in audio stream frequency; + out audio stream pos; +}; + +/** + * A sine wave + */ +interface Synth_WAVE_SIN : SynthModule { + in audio stream pos; + out audio stream outvalue; +}; + +/** + * A module which mixes an arbitary number of audio streams + */ +interface Synth_MULTI_ADD : SynthModule { + in multi audio stream invalue; + out audio stream outvalue; +}; + +/** + * A module which adds two audio streams + */ +interface Synth_ADD : SynthModule { + default in audio stream invalue1,invalue2; + out audio stream outvalue; +}; + +/** + * Multiplies two audio streams + */ +interface Synth_MUL : SynthModule { + in audio stream invalue1,invalue2; + out audio stream outvalue; + default invalue1, invalue2; +}; + +/** + * This plays a wave file + */ +interface Synth_PLAY_WAV : SynthModule { + /** + * How fast should it be played? 1.0 = normal speed + */ + attribute float speed; + /** + * Which file should be played + */ + attribute string filename; + /** + * Is true as soon as the file is finished + */ + readonly attribute boolean finished; + + out audio stream left, right; + default left, right; +}; + +/** + * sends data to a bus - busses are dynamic N:M connections - all signals + * from all uplinks are mixed together, and sent to all downlinks + */ +interface Synth_BUS_UPLINK : SynthModule { + /** + * the name of the bus to use + */ + attribute string busname; + + default in audio stream left,right; +}; + +/** + * receives data from a bus - busses are dynamic N:M connections - all signals + * from all uplinks are mixed together, and sent to all downlinks + */ +interface Synth_BUS_DOWNLINK : SynthModule { + /** + * the name of the bus to use + */ + attribute string busname; + + default out audio stream left,right; +}; + + +/** + * Byte stream to audio conversion object + * + * Converts an asynchronous byte stream to a synchronous audio stream + */ +interface ByteStreamToAudio : SynthModule { + attribute long samplingRate; + attribute long channels; + attribute long bits; + + /** + * is conversion currently running, or is it stalled due to the fact + * that there is not enough input input? + */ + readonly attribute boolean running; + + async in byte stream indata; + + out audio stream left,right; + default left; + default right; +}; + +/** + * Audio to Byte stream conversion object + * + * Converts a synchronous audio stream to an asynchronous byte stream + */ +interface AudioToByteStream : SynthModule { + attribute long samplingRate; + attribute long channels; + attribute long bits; + + async out byte stream outdata; + + in audio stream left,right; + default left; + default right; +}; + +/** + * Base interface for all stereo effects + */ +interface StereoEffect : SynthModule { + default in audio stream inleft, inright; + default out audio stream outleft, outright; +}; + +/** + * this is a simple clipping stereo volume control + */ +interface StereoVolumeControl : StereoEffect { + attribute float scaleFactor; + readonly attribute float currentVolumeLeft; + readonly attribute float currentVolumeRight; +}; + +/** + * A funny FFT scope + */ +interface StereoFFTScope : StereoEffect { + readonly attribute sequence scope; +}; + +/** + * A stack of stereo effects + */ +interface StereoEffectStack : StereoEffect { + /** + * inserts an effect at the top side (= directly after the input) + * + * @returns an ID which can be used to remove the effect again + */ + long insertTop(StereoEffect effect, string name); + + /** + * inserts an effect at the bottom (= close to the output) side + * + * @returns an ID which can be used to remove the effect again + */ + long insertBottom(StereoEffect effect, string name); + + /** + * removes an effect again + */ + void remove(long ID); +}; + +/* + * Audio Manager stuff + */ + +enum AudioManagerDirection { amPlay, amRecord }; + +/** + * Information structure for audio manager clients + */ +struct AudioManagerInfo { + long ID; + string destination; + + AudioManagerDirection direction; + string title, autoRestoreID; +}; + +/** + * an audio manager client + */ +interface AudioManagerClient { + readonly attribute long ID; + attribute AudioManagerDirection direction; + attribute string title, autoRestoreID; + + void constructor(AudioManagerDirection direction, string title, + string autoRestoreID); +}; + +/** + * The audio manager interface + */ +interface AudioManager { + /** + * a list of destinations, where you can play/record data to/from + */ + readonly attribute sequence destinations; + + /** + * a list of clients + */ + readonly attribute sequence clients; + + /** + * this is incremented each time a change is made (i.e. new client attached) + * TODO: SHOULD GO AWAY WITH ATTRIBUTE WATCHING + */ + readonly attribute long changes; + + /** + * this is used to route a client to another destination + */ + void setDestination(long ID, string destination); +}; +/** + * This is a virtual output port, which you use to play data. Where exactly + * this data gets played is managed by the audiomanager. + * + * Creation: there are two ways to initialize a Synth_AMAN_PLAY - one is + * to set title and autoRestoreID to sensible (non empty) values. The other + * is to pass an already initialized AudioManagerClient on the constructor. + */ +interface Synth_AMAN_PLAY : SynthModule { + attribute string title, autoRestoreID; + void constructor(AudioManagerClient client); + + default in audio stream left, right; +}; + +/** + * This is a virtual input port, which you use to record data. Where this + * data comes from is in turn managed by the audiomanager. + * + * Creation: there are two ways to initialize a Synth_AMAN_RECORD - one is + * to set title and autoRestoreID to sensible (non empty) values. The other + * is to pass an already initialized AudioManagerClient on the constructor. + */ +interface Synth_AMAN_RECORD : SynthModule { + attribute string title, autoRestoreID; + void constructor(AudioManagerClient client); + + default out audio stream left, right; +}; + +/* --------------------------------------------------------------------- */ + +/** + * Wraps a datahandle. That is an abstraction for a float value array + * which can be directly loaded data from a file or have some + * processing stages in between (caching, reversing, cropping...) + * which are hidden to this interface. + * In contrast to the underlying C++ API, this datahandle is already + * open()ed after creation, so you can access its information (like + * channelCount) without further action. + * A datahandle normally has one more important function: read() which + * is not wrapped in MCOP because of the overhead of the data + * transfer. (If there is need for sth. like that in the future, + * one could maybe find a solution.) + */ +interface DataHandle { + readonly attribute long bitDepth; + readonly attribute long channelCount; + readonly attribute long valueCount; + /** + * error code open() returned + */ + readonly attribute long errorNo; +}; + +/** + * Represents a datahandle which delivers the data from the underlying + * sourceDatahandle in reverse order. + */ +interface ReversedDataHandle : DataHandle { + void init(DataHandle sourceHandle); +}; + +/** + * Represents a datahandle which delivers an "inner" part of the data + * from the underlying sourceDatahandle. You can cut away parts at the + * start and/or the end with this. + */ +interface CroppedDataHandle : DataHandle { + void init(DataHandle sourceHandle, + long headCutValueCount, + long tailCutValueCount); +}; + +/** + * Represents a datahandle which delivers the data from the underlying + * sourceDatahandle without the "inner" part containing the values + * [cutOffset..cutOffset+cutValueCount-1], which will be cut away. + */ +interface CutDataHandle : DataHandle { + void init(DataHandle sourceHandle, + long cutOffset, + long cutValueCount); +}; + +/** + * DataHandlePlay uses a gsl_wave_osc to play back data from a + * DataHandle using sophisticated anti-aliasing filtering and caching + * techniques. (Though not implemented at the time of writing this, it + * will be optimized for cases where the anti-aliasing is not needed + * because the mixerFrequency equals the current soundserver's.) + */ +interface DataHandlePlay : SynthModule { + /** + * Which data should be played? + */ + attribute DataHandle handle; + /** + * What is the normal mixer frequency the data from the handle + * should be played back at? (default: current mixing frequency + * of the soundserver, e.g. 44100) + */ + attribute float mixerFrequency; + /** + * Which channel of the datahandle should by played? + * (defaults to 0 = the first channel) + */ + attribute long channelIndex; + /** + * How fast should the data be played? + * (defaults to 1.0 = normal speed, see mixerFrequency) + */ + attribute float speed; + /** + * Current position while playing, in fact it's the index in the + * datahandle, so 0 <= pos < handle.valueCount + */ + attribute long pos; + /** + * Is true as soon as the file is finished + */ + readonly attribute boolean finished; + /** + * Can be used to pause and/or continue playing + */ + attribute boolean paused; + + default out audio stream outvalue; + + DataHandlePlay clone(); +}; + +/** + * DataHandle which represents sample data loaded from a file. Note + * that the samples from all channels are interleaved, that is, the + * samples of the first channel in a stereo file are found at offsets + * 0,2,4,6,.. etc. + */ +interface WaveDataHandle : DataHandle { + /** + * Properties of the loaded sample data. Note that those + * properties are only available from a WaveDataHandle, but may be + * available from a DataHandle in the future. + */ + readonly attribute float mixerFrequency; + readonly attribute float oscillatorFrequency; + + /** + * Load the first wavechunk from a file and return true on + * success. A more specific error code is not available at the + * moment. + */ + boolean load(string filename); + + /** + * Load a specific wavechunk from a file and return true on + * success. A more specific error code is not available at the + * moment. + */ + boolean load(string filename, + long waveIndex, long chunkIndex); + + /** + * Return true if and only if a wavechunk was successfully loaded + * from a file. + */ + readonly attribute boolean isLoaded; + + /** + * Creates a DataHandlePlay object with the important attributes + * handle, mixerFrequency and channelCount already set to play + * this WaveDataHandle. + */ + DataHandlePlay createPlayer(); +}; + +}; diff --git a/flow/asyncschedule.cc b/flow/asyncschedule.cc new file mode 100644 index 0000000..b3251a7 --- /dev/null +++ b/flow/asyncschedule.cc @@ -0,0 +1,553 @@ + /* + + Copyright (C) 2000,2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include +#include "asyncschedule.h" + +using namespace std; +using namespace Arts; + +#include "debug.h" +#include + +/* Since this file is a tad bit more complex, here is some basic documentation: + +1) ASyncPort: There are asynchronous ports which are parts of the standard- + flowsystem schedule nodes. Their lifetime starts whenever an asynchronous + stream gets created by the flow system, and ends when the schedule node + gets destroyed. Basically, an ASyncPort has two functions: + + * it is a "Port", which means that it gets connect(), disconnect() and + other calls from the flowsystem + + * it is a "GenericDataChannel", which means that DataPackets can interact + with it + + Although there will be ASyncPorts which only send data and ASyncPorts which + only receive data (there are none that do both), there are no distinct + classes for this. + +2) Standard case: a DataPacket that gets transported over a datachannel locally: + + 1. the user allocates himself a datapacket "packet" + 2. the user calls "packet->send()", which in turn calls + ASyncPort::sendPacket(packet) + 3. the ASyncPort sends the DataPacket to every subscriber (incrementing the + useCount) over the NotificationManager + 4. the NotificationManager delivers the DataPackets to the receiver + 5. eventually, the receiver confirms using "packet->processed()" + 6. the packet informs the ASyncPort::processedPacket() + 7. the packet is freed + +variant (pulling): + + 1. the user gets told by the ASyncPort: produce some data, here is a "packet" + 2. the user calls "packet->send()", which in turn calls + ASyncPort::sendPacket(packet) + 3. the ASyncPort sends the DataPacket to every subscriber (incrementing the + useCount) over the NotificationManager + 4. the NotificationManager delivers the DataPackets to the receiver + 5. eventually, the receiver confirms using "packet->processed()" + 6. the packet informs the ASyncPort::processedPacket() + 7. the ASyncPort restarts with 1. + +3) Remote case: the remote case follows from the local case by adding two extra +things: one object that converts packets from their packet form to a message +(ASyncNetSend), and one object that converts packets from the message form +to a packet again. Effectively, the sending of a single packet looks like +this, then: + + 1-S. the user allocates himself a datapacket "packet" + 2-S. the user calls "packet->send()", which in turn calls + ASyncPort::sendPacket(packet) + 3-S. the ASyncPort sends the DataPacket to every subscriber (incrementing the + useCount) over the NotificationManager + 4-S. the NotificationManager delivers the DataPackets to the ASyncNetSend + 5-S. the ASyncNetSend::notify method gets called, which in turn converts + the packet to a network message + + ... network transfer ... + + 6-R. the ASyncNetReceive::receive method gets called - the method creates + a new data packet, and sends it using the NotificationManager again + 7-R. the NotificationManager delivers the DataPacket to the receiver + 8-R. eventually, the receiver confirms using "packet->processed()" + 9-R. the packet informs the ASyncNetReceive::processedPacket() which + frees the packet and tells the (remote) sender that it went all right + + ... network transfer ... + + 10-S. eventually, ASyncNetSend::processed() gets called, and confirms + the packet using "packet->processed()" + 11-S. the packet informs the ASyncPort::processedPacket() + 12-S. the packet is freed + +variant(pulling): + + works the same as in the local case by exchanging steps 1-S and 12-S + +4) ownership: + + * ASyncPort: is owned by the Object which it is a part of, if the object + dies, ASyncPort dies unconditionally + + * DataPacket: is owned by the GenericDataChannel they are propagated over, + that is, the ASyncPort normally - however if the DataPacket is still in + use (i.e. in state 5 of the local case), it will take responsibility to + free itself once all processed() calls have been collected + + * ASyncNetSend, ASyncNetReceive: own each other, so that if the sender dies, + the connection will die as well, and if the receiver dies, the same happens + +*/ + +#undef DEBUG_ASYNC_TRANSFER + +ASyncPort::ASyncPort(const std::string& name, void *ptr, long flags, + StdScheduleNode* parent) : Port(name, ptr, flags, parent), pull(false) +{ + stream = (GenericAsyncStream *)ptr; + stream->channel = this; + stream->_notifyID = notifyID = parent->object()->_mkNotifyID(); +} + +ASyncPort::~ASyncPort() +{ + /* + * tell all outstanding packets that we don't exist any longer, so that + * if they feel like they need to confirm they have been processed now, + * they don't talk to an no longer existing object about it + */ + while(!sent.empty()) + { + sent.front()->channel = 0; + sent.pop_front(); + } + + /* disconnect remote connections (if present): the following things will + * need to be ensured here, since we are being deleted: + * + * - the senders should not talk to us after our destructor + * - all of our connections need to be disconnected + * - every connection needs to be closed exactly once + * + * (closing a connection can cause reentrancy due to mcop communication) + */ + while(!netSenders.empty()) + netSenders.front()->disconnect(); + + FlowSystemReceiver receiver = netReceiver; + if(!receiver.isNull()) + receiver.disconnect(); +} + +//-------------------- GenericDataChannel interface ------------------------- + +void ASyncPort::setPull(int packets, int capacity) +{ + pullNotification.receiver = parent->object(); + pullNotification.ID = notifyID; + pullNotification.internal = 0; + pull = true; + + for(int i=0;icreatePacket(capacity); + packet->useCount = 0; + pullNotification.data = packet; + NotificationManager::the()->send(pullNotification); + } +} + +void ASyncPort::endPull() +{ + pull = false; + // TODO: maybe remove all pending pull packets here +} + +void ASyncPort::processedPacket(GenericDataPacket *packet) +{ + int count = 0; + list::iterator i = sent.begin(); + while(i != sent.end()) + { + if(*i == packet) + { + count++; + i = sent.erase(i); + } + else i++; + } + assert(count == 1); + +#ifdef DEBUG_ASYNC_TRANSFER + cout << "port::processedPacket" << endl; +#endif + assert(packet->useCount == 0); + if(pull) + { + pullNotification.data = packet; + NotificationManager::the()->send(pullNotification); + } + else + { + stream->freePacket(packet); + } +} + +void ASyncPort::sendPacket(GenericDataPacket *packet) +{ + bool sendOk = false; + +#ifdef DEBUG_ASYNC_TRANSFER + cout << "port::sendPacket" << endl; +#endif + + if(packet->size > 0) + { + vector::iterator i; + for(i=subscribers.begin(); i != subscribers.end(); i++) + { + Notification n = *i; + n.data = packet; + packet->useCount++; +#ifdef DEBUG_ASYNC_TRANSFER + cout << "sending notification " << n.ID << endl; +#endif + NotificationManager::the()->send(n); + sendOk = true; + } + } + + if(sendOk) + sent.push_back(packet); + else + stream->freePacket(packet); +} + +//----------------------- Port interface ------------------------------------ + +void ASyncPort::connect(Port *xsource) +{ + arts_debug("port(%s)::connect",_name.c_str()); + + ASyncPort *source = xsource->asyncPort(); + assert(source); + addAutoDisconnect(xsource); + + Notification n; + n.receiver = parent->object(); + n.ID = notifyID; + n.internal = 0; + source->subscribers.push_back(n); +} + +void ASyncPort::disconnect(Port *xsource) +{ + arts_debug("port::disconnect"); + + ASyncPort *source = xsource->asyncPort(); + assert(source); + removeAutoDisconnect(xsource); + + // remove our subscription from the source object + vector::iterator si; + for(si = source->subscribers.begin(); si != source->subscribers.end(); si++) + { + if(si->receiver == parent->object()) + { + source->subscribers.erase(si); + return; + } + } + + // there should have been exactly one, so this shouldn't be reached + assert(false); +} + +ASyncPort *ASyncPort::asyncPort() +{ + return this; +} + +GenericAsyncStream *ASyncPort::receiveNetCreateStream() +{ + return stream->createNewStream(); +} + +NotificationClient *ASyncPort::receiveNetObject() +{ + return parent->object(); +} + +long ASyncPort::receiveNetNotifyID() +{ + return notifyID; +} + +// Network transparency +void ASyncPort::addSendNet(ASyncNetSend *netsend) +{ + Notification n; + n.receiver = netsend; + n.ID = netsend->notifyID(); + n.internal = 0; + subscribers.push_back(n); + netSenders.push_back(netsend); +} + +void ASyncPort::removeSendNet(ASyncNetSend *netsend) +{ + arts_return_if_fail(netsend != 0); + netSenders.remove(netsend); + + vector::iterator si; + for(si = subscribers.begin(); si != subscribers.end(); si++) + { + if(si->receiver == netsend) + { + subscribers.erase(si); + return; + } + } + arts_warning("Failed to remove ASyncNetSend (%p) from ASyncPort", netsend); +} + +void ASyncPort::setNetReceiver(ASyncNetReceive *receiver) +{ + arts_return_if_fail(receiver != 0); + + FlowSystemReceiver r = FlowSystemReceiver::_from_base(receiver->_copy()); + netReceiver = r; +} + +void ASyncPort::disconnectRemote(const string& dest) +{ + list::iterator i; + + for(i = netSenders.begin(); i != netSenders.end(); i++) + { + if((*i)->dest() == dest) + { + (*i)->disconnect(); + return; + } + } + arts_warning("failed to disconnect %s in ASyncPort", dest.c_str()); +} + +ASyncNetSend::ASyncNetSend(ASyncPort *ap, const std::string& dest) : ap(ap) +{ + _dest = dest; + ap->addSendNet(this); +} + +ASyncNetSend::~ASyncNetSend() +{ + while(!pqueue.empty()) + { + pqueue.front()->processed(); + pqueue.pop(); + } + if(ap) + { + ap->removeSendNet(this); + ap = 0; + } +} + +long ASyncNetSend::notifyID() +{ + return 1; +} + +void ASyncNetSend::notify(const Notification& notification) +{ + // got a packet? + assert(notification.ID == notifyID()); + GenericDataPacket *dp = (GenericDataPacket *)notification.data; + pqueue.push(dp); + + /* + * since packets are delivered asynchronously, and since disconnection + * involves communication, it might happen that we get a packet without + * actually being connected any longer - in that case, silently forget it + */ + if(!receiver.isNull()) + { + // put it into a custom data message and send it to the receiver + Buffer *buffer = receiver._allocCustomMessage(receiveHandlerID); + dp->write(*buffer); + receiver._sendCustomMessage(buffer); + } +} + +void ASyncNetSend::processed() +{ + assert(!pqueue.empty()); + pqueue.front()->processed(); + pqueue.pop(); +} + +void ASyncNetSend::setReceiver(FlowSystemReceiver newReceiver) +{ + receiver = newReceiver; + receiveHandlerID = newReceiver.receiveHandlerID(); +} + +void ASyncNetSend::disconnect() +{ + /* since disconnection will cause destruction (most likely immediate), + * we'll reference ourselves ... */ + _copy(); + + if(!receiver.isNull()) + { + FlowSystemReceiver r = receiver; + receiver = FlowSystemReceiver::null(); + r.disconnect(); + } + if(ap) + { + ap->removeSendNet(this); + ap = 0; + } + + _release(); +} + +string ASyncNetSend::dest() +{ + return _dest; +} + +/* dispatching function for custom message */ + +static void _dispatch_ASyncNetReceive_receive(void *object, Buffer *buffer) +{ + ((ASyncNetReceive *)object)->receive(buffer); +} + +ASyncNetReceive::ASyncNetReceive(ASyncPort *port, FlowSystemSender sender) +{ + port->setNetReceiver(this); + stream = port->receiveNetCreateStream(); + stream->channel = this; + this->sender = sender; + /* stream->_notifyID = _mkNotifyID(); */ + + gotPacketNotification.ID = port->receiveNetNotifyID(); + gotPacketNotification.receiver = port->receiveNetObject(); + gotPacketNotification.internal = 0; + _receiveHandlerID = + _addCustomMessageHandler(_dispatch_ASyncNetReceive_receive,this); +} + +ASyncNetReceive::~ASyncNetReceive() +{ + /* tell outstanding packets that we don't exist any longer */ + while(!sent.empty()) + { + sent.front()->channel = 0; + sent.pop_front(); + } + delete stream; +} + +long ASyncNetReceive::receiveHandlerID() +{ + return _receiveHandlerID; +} + +void ASyncNetReceive::receive(Buffer *buffer) +{ + GenericDataPacket *dp = stream->createPacket(512); + dp->read(*buffer); + dp->useCount = 1; + gotPacketNotification.data = dp; + NotificationManager::the()->send(gotPacketNotification); + sent.push_back(dp); +} + +/* + * It will happen that this routine is called in time critical situations, + * such as: while audio calculation is running, and must be finished in + * time. The routine is mostly harmless, because sender->processed() is + * a oneway function, which just queues the buffer for sending and returns + * back, so it should return at once. + * + * However there is an exception upon first call: when sender->processed() + * is called for the first time, the method processed has still to be looked + * up. Thus, a synchronous call to _lookupMethod is made. That means, upon + * first call, the method will send out an MCOP request and block until the + * remote process tells that id. + */ +void ASyncNetReceive::processedPacket(GenericDataPacket *packet) +{ + /* + * HACK! Upon disconnect, strange things will happen. One of them is + * that we might, for the reason of not being referenced any longer, + * cease to exist without warning. Another is that our nice "sender" + * reference will get a null reference without warning, see disconnect + * code (which will cause the attached stub to also disappear). As + * those objects (especially the stub) are not prepared for not + * being there any more in the middle of whatever they do, we here + * explicitly reference us, and them, *again*, so that no evil things + * will happen. A general solution for this would be garbage collection + * in a timer, but until this is implemented (if it ever will become + * implemented), we'll live with this hack. + */ + _copy(); + sent.remove(packet); + stream->freePacket(packet); + if(!sender.isNull()) + { + FlowSystemSender xsender = sender; + xsender.processed(); + } + _release(); +} + +void ASyncNetReceive::disconnect() +{ + if(!sender.isNull()) + { + FlowSystemSender s = sender; + sender = FlowSystemSender::null(); + s.disconnect(); + } +} + +void ASyncNetReceive::sendPacket(GenericDataPacket *) +{ + assert(false); +} + +void ASyncNetReceive::setPull(int, int) +{ + assert(false); +} + +void ASyncNetReceive::endPull() +{ + assert(false); +} diff --git a/flow/asyncschedule.h b/flow/asyncschedule.h new file mode 100644 index 0000000..0477c9a --- /dev/null +++ b/flow/asyncschedule.h @@ -0,0 +1,134 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifndef ASYNCSCHEDULE_H +#define ASYNCSCHEDULE_H + +#include "gslschedule.h" +#include "datapacket.h" +#include "weakreference.h" + +#include + +/* + * BC - Status (2002-03-08): ASyncNetSend, ASyncNetReceive, ASyncPort. + * + * None of these classes is considered part of the public API. Do NOT use it + * in your apps. These are part of the implementation of libartsflow's + * StdFlowSystem, and subject to change with the needs of it. + */ + +namespace Arts { + +class ASyncPort; +class ASyncNetSend : public FlowSystemSender_skel +{ +protected: + ASyncPort *ap; + std::queue pqueue; + FlowSystemReceiver receiver; + long receiveHandlerID; + std::string _dest; + +public: + ASyncNetSend(ASyncPort *ap, const std::string& dest); + ~ASyncNetSend(); + long notifyID(); + std::string dest(); + + /* this overwrites the Object::notify function */ + void notify(const Notification& notification); + void processed(); + void setReceiver(FlowSystemReceiver receiver); + void disconnect(); +}; + +class ASyncNetReceive : public FlowSystemReceiver_skel, + public GenericDataChannel +{ +protected: + GenericAsyncStream *stream; + FlowSystemSender sender; + Notification gotPacketNotification; + std::list sent; + long _receiveHandlerID; + +public: + ASyncNetReceive(ASyncPort *port, FlowSystemSender sender); + ~ASyncNetReceive(); + + // GenericDataChannel interface + void processedPacket(GenericDataPacket *packet); + void sendPacket(GenericDataPacket *packet); + void setPull(int packets, int capacity); + void endPull(); + + // FlowSystemReceiver interface + + long receiveHandlerID(); + void disconnect(); + void receive(Buffer *buffer); // custom data receiver +}; + +class ASyncPort :public Port, public GenericDataChannel { +protected: + long notifyID; + std::vector subscribers; + std::list sent; + std::list netSenders; + WeakReference netReceiver; + + GenericAsyncStream *stream; + + bool pull; + Notification pullNotification; + +public: + // GenericDataChannel interface + void processedPacket(GenericDataPacket *packet); + void sendPacket(GenericDataPacket *packet); + void setPull(int packets, int capacity); + void endPull(); + + // Port interface + ASyncPort(const std::string& name, void *ptr, long flags, + StdScheduleNode* parent); + ~ASyncPort(); + + void connect(Port *port); + void disconnect(Port *port); + ASyncPort *asyncPort(); + + // Network transparency + void addSendNet(ASyncNetSend *netsend); // send + void removeSendNet(ASyncNetSend *netsend); + void disconnectRemote(const std::string& dest); + + long receiveNetNotifyID(); // receive + GenericAsyncStream *receiveNetCreateStream(); + NotificationClient *receiveNetObject(); + void setNetReceiver(ASyncNetReceive *receiver); +}; + +} + +#endif /* ASYNCSCHEDULE_H */ diff --git a/flow/audioio.cc b/flow/audioio.cc new file mode 100644 index 0000000..e5924ab --- /dev/null +++ b/flow/audioio.cc @@ -0,0 +1,165 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "audioio.h" +#include +#include +#include +#include + +using namespace Arts; +using namespace std; + +class Arts::AudioIOPrivate { +public: + map paramMap; + map paramStrMap; +}; + +AudioIO::AudioIO() :d(new AudioIOPrivate) +{ +} + +AudioIO::~AudioIO() +{ + delete d; +} + +int& AudioIO::param(AudioParam param) +{ + /* + * returns d->paramMap[param], initializes new elements with -1 (for those + * parameters not handled explicitly by the derived AudioIO* class). + */ + + map::iterator pi = d->paramMap.find(param); + if(pi == d->paramMap.end()) + { + int& result = d->paramMap[param]; + result = -1; + return result; + } + else return pi->second; +} + +string& AudioIO::paramStr(AudioParam param) +{ + return d->paramStrMap[param]; +} + +void AudioIO::setParamStr(AudioParam p, const char *value) +{ + paramStr(p) = value; +} + +void AudioIO::setParam(AudioParam p, int& value) +{ + param(p) = value; +} + +int AudioIO::getParam(AudioParam p) +{ + return param(p); +} + +const char *AudioIO::getParamStr(AudioParam p) +{ + return paramStr(p).c_str(); +} + +/* ---- factories ---- */ + +static list *audioIOFactories = 0; + +AudioIO *AudioIO::createAudioIO(const char *name) +{ + if(audioIOFactories) + { + list::iterator i; + for(i = audioIOFactories->begin(); i != audioIOFactories->end(); i++) + { + AudioIOFactory *factory = *i; + + if(strcmp(factory->name(),name) == 0) + return factory->createAudioIO(); + } + } + return 0; +} + +int AudioIO::queryAudioIOCount() +{ + return audioIOFactories->size(); +} + +int AudioIO::queryAudioIOParam(int /*audioIO*/, AudioParam /*p*/) +{ + return 0; +} + +const char *AudioIO::queryAudioIOParamStr(int audioIO, AudioParam p) +{ + list::iterator i = audioIOFactories->begin(); + + while(audioIO && i != audioIOFactories->end()) { i++; audioIO--; } + if(i == audioIOFactories->end()) return 0; + + switch(p) + { + case name: + return (*i)->name(); + case fullName: + return (*i)->fullName(); + default: + return 0; + } +} + +void AudioIO::addFactory(AudioIOFactory *factory) +{ + if(!audioIOFactories) + audioIOFactories = new list; + + audioIOFactories->push_back(factory); +} + +void AudioIO::removeFactory(AudioIOFactory *factory) +{ + assert(audioIOFactories); + + audioIOFactories->remove(factory); + if(audioIOFactories->empty()) + { + delete audioIOFactories; + audioIOFactories = 0; + } +} + +void AudioIOFactory::startup() +{ + AudioIO::addFactory(this); +} + +void AudioIOFactory::shutdown() +{ + AudioIO::removeFactory(this); +} diff --git a/flow/audioio.h b/flow/audioio.h new file mode 100644 index 0000000..ade96e2 --- /dev/null +++ b/flow/audioio.h @@ -0,0 +1,145 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifndef ARTS_AUDIOIO_H +#define ARTS_AUDIOIO_H + +#include +#include +#include "arts_export.h" +/* + * BC - Status (2002-03-08): AudioIO, AudioIOFactory + * + * Right now, these classes are considered an implementation detail. No binary + * compatibility guaranteed, its safe to add virtual methods when required. + */ + +/* + * The AudioIO class - it is used as follows: + * + * 1. check the settings with getParam, modify what you don't like + * 2. call open -> print getInfo(lastError) if it failed (returned false) + * 3. check whether the settings are still what you expected them to + * be (as the AudioIO class will maybe only know after open if the + * requested parameters can be achieved) + */ + +namespace Arts { + +class AudioIOPrivate; +class AudioIOFactory; + +class ARTS_EXPORT AudioIO { +private: + class AudioIOPrivate *d; + +public: + enum AudioParam { +/* the following has to be supported */ + samplingRate = 1, /* usually 4000..48000 (Hz) */ + channels = 2, /* usually 1 (mono) or 2 (stereo) */ + format = 3, /* 8 = 8bit unsigned + * 16 = 16bit signed little endian + * 17 = 16bit signed big endian + * 32 = 32bit float */ + +/* the following -can- be supported (value=-1 if they are not) */ + direction = 101, /* 1 = read, 2 = write, 3 = read|write */ + fragmentCount = 102,/* usually 3..16 (to control latency) */ + fragmentSize = 103, /* usually 256,512,...8192 (a 2^N value) */ + canRead = 104, /* the amount of bytes that can be read */ + canWrite = 105, /* the amount of bytes that can be written */ + selectReadFD = 106, /* filedescriptor to be select()ed on for reading */ + selectWriteFD = 107,/* filedescriptor to be select()ed on for writing */ + autoDetect = 108, /* 0 = don't use this as default + * 1 or higher = preference of using this as default + * + * if nothing else is specified, aRts asks all + * available AudioIO classes for the autoDetect + * value and chooses the one which returned the + * highest number */ + +/* string parameters that have to be supported */ + lastError = 201, /* the last error message as human readable text */ + +/* string parameters that -can- be supported */ + deviceName = 301, /* name of the device to open */ + +/* class parameters: same semantics as above */ + name = 1201, /* name of the driver (i.e. oss) */ + fullName = 1202 /* full name (i.e. Open Sound System) */ + }; + + enum { + directionRead = 1, + directionWrite = 2, + directionReadWrite = 3 + }; + + AudioIO(); + virtual ~AudioIO(); + + virtual void setParamStr(AudioParam param, const char *value); + virtual void setParam(AudioParam param, int& value); + virtual int getParam(AudioParam param); + virtual const char *getParamStr(AudioParam param); + + virtual bool open() = 0; + virtual void close() = 0; + virtual int read(void *buffer, int size) = 0; + virtual int write(void *buffer, int size) = 0; + +/* ---- factory querying stuff ---- */ + static int queryAudioIOCount(); + static int queryAudioIOParam(int audioIO, AudioParam param); + static const char *queryAudioIOParamStr(int audioIO, AudioParam param); + +/* ---- factory stuff ---- */ + static AudioIO *createAudioIO(const char *name); + static void addFactory(AudioIOFactory *factory); + static void removeFactory(AudioIOFactory *factory); + +protected: + int& param(AudioParam param); + std::string& paramStr(AudioParam param); +}; + +class ARTS_EXPORT AudioIOFactory : public StartupClass { +public: + void startup(); + void shutdown(); + virtual AudioIO *createAudioIO() = 0; + virtual const char *name() = 0; + virtual const char *fullName() = 0; +}; + +} + +#define REGISTER_AUDIO_IO(impl,implName,implFullName) \ + static class AudioIOFactory ## impl : public AudioIOFactory { \ + public: \ + AudioIO *createAudioIO() { return new impl(); } \ + virtual const char *name() { return implName; } \ + virtual const char *fullName() { return implFullName; } \ + } The_ ## impl ## _Factory /* <- add semicolon when calling this macro */ + +#endif /* ARTS_AUDIOIO_H */ diff --git a/flow/audioioaix.cc b/flow/audioioaix.cc new file mode 100644 index 0000000..f36e9db --- /dev/null +++ b/flow/audioioaix.cc @@ -0,0 +1,390 @@ +/* + + Copyright (C) 2001 Carsten Griwodz + griff@ifi.uio.no + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef _AIX + +/* + * The audio header files exist even if there is not soundcard the + * the AIX machine. You won't be able to compile this code on AIX3 + * which had ACPA support, so /dev/acpa is not checked here. + * I have no idea whether the Ultimedia Audio Adapter is actually + * working or what it is right now. + * For PCI machines including PowerSeries 850, baud or paud should + * work. The DSP (MWave?) of the 850 laptops may need microcode + * download. This is not implemented. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef BIG_ENDIAN +#include + +#ifndef AUDIO_BIG_ENDIAN +#define AUDIO_BIG_ENDIAN BIG_ENDIAN +#endif + +#include "debug.h" +#include "audioio.h" + +namespace Arts { + +class AudioIOAIX : public AudioIO { + int openDevice(); + +protected: + int audio_fd; + +public: + AudioIOAIX(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOAIX,"paud","Personal Audio Device"); +}; + +using namespace std; +using namespace Arts; + +int AudioIOAIX::openDevice() +{ + char devname[14]; + int fd; + for ( int dev=0; dev<4; dev++ ) + { + for ( int chan=1; chan<8; chan++ ) + { + sprintf(devname,"/dev/paud%d/%d",dev,chan); + fd = ::open (devname, O_WRONLY, 0); + if ( fd >= 0 ) + { + paramStr(deviceName) = devname; + return fd; + } + sprintf(devname,"/dev/baud%d/%d",dev,chan); + fd = ::open (devname, O_WRONLY, 0); + if ( fd >= 0 ) + { + paramStr(deviceName) = devname; + return fd; + } + } + } + return -1; +} + +AudioIOAIX::AudioIOAIX() +{ + int fd = openDevice(); + if( fd >= 0 ) + { + audio_status audioStatus; + memset( &audioStatus, 0, sizeof(audio_status) ); + ioctl(fd, AUDIO_STATUS, &audioStatus); + + audio_buffer audioBuffer; + memset( &audioBuffer, 0, sizeof(audio_buffer) ); + ioctl(fd, AUDIO_BUFFER, &audioBuffer); + + ::close( fd ); + + /* + * default parameters + */ + param(samplingRate) = audioStatus.srate; + param(fragmentSize) = audioStatus.bsize; + param(fragmentCount) = audioBuffer.write_buf_cap / audioStatus.bsize; + param(channels) = audioStatus.channels; + param(direction) = 2; + + param(format) = ( audioStatus.bits_per_sample==8 ) ? 8 + : ( ( audioStatus.flags & AUDIO_BIG_ENDIAN ) ? 17 : 16 ); + } +} + +bool AudioIOAIX::open() +{ + string& _error = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _format = param(format); + + int mode; + + switch( param(direction) ) + { + case 1 : mode = O_RDONLY | O_NDELAY; break; + case 2 : mode = O_WRONLY | O_NDELAY; break; + case 3 : + _error = "open device twice to RDWR"; + return false; + default : + _error = "invalid direction"; + return false; + } + + audio_fd = ::open(_deviceName.c_str(), mode, 0); + + if(audio_fd == -1) + { + _error = "device "; + _error += _deviceName.c_str(); + _error += " can't be opened ("; + _error += strerror(errno); + _error += ")"; + return false; + } + + if( (_channels!=1) && (_channels!=2) ) + { + _error = "internal error; set channels to 1 (mono) or 2 (stereo)"; + + close(); + return false; + } + + // int requeststereo = stereo; + + // int speed = _samplingRate; + + audio_init audioInit; + memset( &audioInit, 0, sizeof(audio_init) ); + audioInit.srate = _samplingRate; + audioInit.bits_per_sample = ((_format==8)?8:16); + audioInit.bsize = _fragmentSize; + audioInit.mode = PCM; + audioInit.channels = _channels; + audioInit.flags = 0; + audioInit.flags |= (_format==17) ? AUDIO_BIG_ENDIAN : 0; + audioInit.flags |= (_format==8) ? 0 : SIGNED; + audioInit.operation = (param(direction)==1) ? RECORD : PLAY; + + if ( ioctl(audio_fd, AUDIO_INIT, &audioInit) < 0 ) + { + _error = "AUDIO_INIT failed - "; + _error += strerror(errno); + switch ( audioInit.rc ) + { + case 1 : + _error += "Couldn't set audio format: DSP can't do play requests"; + break; + case 2 : + _error += "Couldn't set audio format: DSP can't do record requests"; + break; + case 4 : + _error += "Couldn't set audio format: request was invalid"; + break; + case 5 : + _error += "Couldn't set audio format: conflict with open's flags"; + break; + case 6 : + _error += "Couldn't set audio format: out of DSP MIPS or memory"; + break; + default : + _error += "Couldn't set audio format: not documented in sys/audio.h"; + break; + } + + close(); + return false; + } + + if (audioInit.channels != _channels) + { + _error = "audio device doesn't support number of requested channels"; + close(); + return false; + } + + switch( _format ) + { + case 8 : + if (audioInit.flags&AUDIO_BIG_ENDIAN==1) + { + _error = "setting little endian format failed"; + close(); + return false; + } + if (audioInit.flags&SIGNED==1) + { + _error = "setting unsigned format failed"; + close(); + return false; + } + break; + case 16 : + if (audioInit.flags&AUDIO_BIG_ENDIAN==1) + { + _error = "setting little endian format failed"; + close(); + return false; + } + if (audioInit.flags&SIGNED==0) + { + _error = "setting signed format failed"; + close(); + return false; + } + break; + case 17 : + if (audioInit.flags&AUDIO_BIG_ENDIAN==0) + { + _error = "setting big endian format failed"; + close(); + return false; + } + if (audioInit.flags&SIGNED==0) + { + _error = "setting signed format failed"; + close(); + return false; + } + break; + default : + break; + } + + /* + * Some soundcards seem to be able to only supply "nearly" the requested + * sampling rate, especially PAS 16 cards seem to quite radical supplying + * something different than the requested sampling rate ;) + * + * So we have a quite large tolerance here (when requesting 44100 Hz, it + * will accept anything between 38690 Hz and 49510 Hz). Most parts of the + * aRts code will do resampling where appropriate, so it shouldn't affect + * sound quality. + */ + int tolerance = _samplingRate/10+1000; + + if (abs(audioInit.srate - _samplingRate) > tolerance) + { + _error = "can't set requested samplingrate"; + + char details[80]; + sprintf(details," (requested rate %d, got rate %ld)", + _samplingRate, audioInit.srate); + _error += details; + + close(); + return false; + } + _samplingRate = audioInit.srate; + + _fragmentSize = audioInit.bsize; + _fragmentCount = audioInit.bsize / audioInit.bits_per_sample; + + audio_buffer buffer_info; + ioctl(audio_fd, AUDIO_BUFFER, &buffer_info); + _fragmentCount = buffer_info.write_buf_cap / audioInit.bsize; + + + artsdebug("buffering: %d fragments with %d bytes " + "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, + (float)(_fragmentSize*_fragmentCount) / + (float)(2.0 * _samplingRate * _channels)*1000.0); + + return true; +} + +void AudioIOAIX::close() +{ + ::close(audio_fd); +} + +void AudioIOAIX::setParam(AudioParam p, int& value) +{ + param(p) = value; +} + +int AudioIOAIX::getParam(AudioParam p) +{ + audio_buffer info; + switch(p) + { + case canRead: + ioctl(audio_fd, AUDIO_BUFFER, &info); + return (info.read_buf_cap - info.read_buf_size); + break; + + case canWrite: + ioctl(audio_fd, AUDIO_BUFFER, &info); + return (info.write_buf_cap - info.write_buf_size); + break; + + case selectReadFD: + return (param(direction) & directionRead)?audio_fd:-1; + break; + + case selectWriteFD: + return (param(direction) & directionWrite)?audio_fd:-1; + break; + + case autoDetect: + /* You may prefer OSS if it works, e.g. on 43P 240 + * or you may prefer UMS, if anyone bothers to write + * a module for it. + */ + return 2; + break; + + default: + return param(p); + break; + } +} + +int AudioIOAIX::read(void *buffer, int size) +{ + arts_assert(audio_fd != 0); + return ::read(audio_fd,buffer,size); +} + +int AudioIOAIX::write(void *buffer, int size) +{ + arts_assert(audio_fd != 0); + return ::write(audio_fd,buffer,size); +} + +#endif + diff --git a/flow/audioioalsa.cc b/flow/audioioalsa.cc new file mode 100644 index 0000000..303db16 --- /dev/null +++ b/flow/audioioalsa.cc @@ -0,0 +1,561 @@ + /* + + Copyright (C) 2000,2001 Jozef Kosoru + jozef.kosoru@pobox.sk + (C) 2000,2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/** + * only compile 'alsa' AudioIO class if configure thinks it is a good idea + */ +#ifdef HAVE_LIBASOUND + +#ifdef HAVE_ALSA_ASOUNDLIB_H +#include +#elif defined(HAVE_SYS_ASOUNDLIB_H) +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_SYS_SELECT_H +#include // Needed on some systems. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "audioio.h" + +namespace Arts { + +class AudioIOALSA : public AudioIO { +protected: + int audio_read_fd; + int audio_write_fd; + int requestedFragmentSize; + int requestedFragmentCount; + + enum BufferMode{block, stream}; + int m_card; + int m_device; + int m_format; + BufferMode m_bufferMode; + + snd_pcm_t *m_pcm_handle; + snd_pcm_channel_info_t m_cinfo; + snd_pcm_format_t m_cformat; + snd_pcm_channel_params_t m_params; + snd_pcm_channel_setup_t m_setup; + + int setPcmParams(const int channel); + void checkCapabilities(); + +public: + AudioIOALSA(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOALSA,"alsa","Advanced Linux Sound Architecture"); +}; + +using namespace std; +using namespace Arts; + +AudioIOALSA::AudioIOALSA() +{ + param(samplingRate) = 44100; + paramStr(deviceName) = "/dev/dsp"; //!! alsa doesn't need this + requestedFragmentSize = param(fragmentSize) = 1024; + requestedFragmentCount = param(fragmentCount) = 7; + param(channels) = 2; + param(direction) = directionWrite; + + /* + * default parameters + */ + m_card = snd_defaults_pcm_card(); //!! need interface !! + m_device = snd_defaults_pcm_device(); //!! +#ifdef WORDS_BIGENDIAN + m_format = SND_PCM_SFMT_S16_BE; +#else + m_format = SND_PCM_SFMT_S16_LE; +#endif + m_bufferMode = block; //block/stream (stream mode doesn't work yet) + + if(m_card >= 0) { + char* cardname = 0; + + if(snd_card_get_name(m_card, &cardname) == 0 && cardname != 0) + { + //!! thats not what devicename is intended to do + //!! devicename is an input information into + //!! the "driver", to select which card to use + //!! not an output information + paramStr(deviceName) = cardname; + free(cardname); + } + } +} + +bool AudioIOALSA::open() +{ + string& _error = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _direction = param(direction); + int& _format = param(format); + + /* + * initialize format - TODO: implement fallback (i.e. if no format given, + * it should try 16bit first, then fall back to 8bit) + */ + switch(_format) + { + default: _format = 16; + + case 16: // 16bit, signed little endian + m_format = SND_PCM_SFMT_S16_LE; + break; + + case 17: // 16bit, signed big endian + m_format = SND_PCM_SFMT_S16_BE; + break; + + case 8: // 8bit, unsigned + m_format = SND_PCM_SFMT_U8; + break; + } + + /* open pcm device */ + int mode = SND_PCM_OPEN_NONBLOCK; + + if(_direction == directionReadWrite) + mode |= SND_PCM_OPEN_DUPLEX; + else if(_direction == directionWrite) + mode |= SND_PCM_OPEN_PLAYBACK; + else + { + _error = "invalid direction"; + return false; + } + + int err; + if((err = snd_pcm_open(&m_pcm_handle, m_card, m_device, mode)) < 0) { + _error = "device: "; + _error += _deviceName.c_str(); + _error += " can't be opened ("; + _error += snd_strerror(err); + _error += ")"; + return false; + } + else { + artsdebug("ALSA driver: %s", _deviceName.c_str()); + } + + snd_pcm_nonblock_mode(m_pcm_handle, 0); + + /* flush buffers */ + (void)snd_pcm_capture_flush(m_pcm_handle); + if(_direction & directionRead) + (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE); + if(_direction & directionWrite) + (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK); + + /* check device capabilities */ + checkCapabilities(); + + /* set the fragment settings to what the user requested */ + _fragmentSize = requestedFragmentSize; + _fragmentCount = requestedFragmentCount; + + /* set PCM communication parameters */ + if((_direction & directionRead) && setPcmParams(SND_PCM_CHANNEL_CAPTURE)) + return false; + if((_direction & directionWrite) && setPcmParams(SND_PCM_CHANNEL_PLAYBACK)) + return false; + + /* prepare channel */ + if((_direction & directionRead) && + snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE) < 0) + { + _error = "Unable to prepare capture channel!"; + return false; + } + if((_direction & directionWrite) && + snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK) < 0) + { + _error = "Unable to prepare playback channel!"; + return false; + } + + /* obtain current PCM setup (may differ from requested one) */ + (void)memset(&m_setup, 0, sizeof(m_setup)); + + m_setup.channel = SND_PCM_CHANNEL_PLAYBACK; + if(snd_pcm_channel_setup(m_pcm_handle, &m_setup) < 0) { + _error = "Unable to obtain channel setup!"; + return false; + } + + /* check samplerate */ + const int tolerance = _samplingRate/10+1000; + if(abs(m_setup.format.rate-_samplingRate) > tolerance) + { + _error = "Can't set requested sampling rate!"; + char details[80]; + sprintf(details," (requested rate %d, got rate %d)", + _samplingRate, m_setup.format.rate); + _error += details; + return false; + } + _samplingRate = m_setup.format.rate; + + /* check format */ + if(m_setup.format.format != m_format) { + _error = "Can't set requested format:"; + _error += snd_pcm_get_format_name(m_format); + return false; + } + + /* check voices */ + if(m_setup.format.voices != _channels) { + _error = "Audio device doesn't support number of requested channels!"; + return false; + } + + /* update fragment settings with what we got */ + switch(m_bufferMode) { + case block: + _fragmentSize = m_setup.buf.block.frag_size; + _fragmentCount = m_setup.buf.block.frags_max-1; + break; + case stream: + _fragmentSize = m_setup.buf.stream.queue_size; + _fragmentCount = 1; + break; + } + + artsdebug("buffering: %d fragments with %d bytes " + "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, + (float)(_fragmentSize*_fragmentCount) / + (float)(2.0 * _samplingRate * _channels)*1000.0); + + /* obtain PCM file descriptor(s) */ + audio_read_fd = audio_write_fd = -1; + + if(_direction & directionRead) + audio_read_fd = snd_pcm_file_descriptor(m_pcm_handle, + SND_PCM_CHANNEL_CAPTURE); + if(_direction & directionWrite) + audio_write_fd = snd_pcm_file_descriptor(m_pcm_handle, + SND_PCM_CHANNEL_PLAYBACK); + + /* start recording */ + if((_direction & directionRead) && snd_pcm_capture_go(m_pcm_handle)) { + _error = "Can't start recording!"; + return false; + } + + return true; +} + +void AudioIOALSA::close() +{ + int& _direction = param(direction); + if(_direction & directionRead) + (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE); + if(_direction & directionWrite) + (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK); + (void)snd_pcm_close(m_pcm_handle); +} + +void AudioIOALSA::setParam(AudioParam p, int& value) +{ + switch(p) + { + case fragmentSize: + param(p) = requestedFragmentSize = value; + break; + case fragmentCount: + param(p) = requestedFragmentCount = value; + break; + default: + param(p) = value; + break; + } +} + +int AudioIOALSA::getParam(AudioParam p) +{ + snd_pcm_channel_status_t status; + (void)memset(&status, 0, sizeof(status)); + + switch(p) + { + case canRead: + status.channel = SND_PCM_CHANNEL_CAPTURE; + if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { + arts_warning("Capture channel status error!"); + return -1; + } + return status.free; + break; + + case canWrite: + status.channel = SND_PCM_CHANNEL_PLAYBACK; + if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { + arts_warning("Playback channel status error!"); + return -1; + } + return status.free; + break; + + case selectReadFD: + return audio_read_fd; + break; + + case selectWriteFD: + return audio_write_fd; + break; + + case autoDetect: + /* + * that the ALSA driver could be compiled doesn't say anything + * about whether it will work (the user might be using an OSS + * kernel driver) so we'll use a value less than the OSS one + * here, because OSS will most certainly work (ALSA's OSS emu) + */ + return 5; + break; + + default: + return param(p); + break; + } +} + +int AudioIOALSA::read(void *buffer, int size) +{ + int length; + do { + length = snd_pcm_read(m_pcm_handle, buffer, size); + } while (length == -EINTR); + if(length == -EPIPE) { + snd_pcm_channel_status_t status; + (void)memset(&status, 0, sizeof(status)); + status.channel = SND_PCM_CHANNEL_CAPTURE; + if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { + arts_info("Capture channel status error!"); + return -1; + } + else if(status.status == SND_PCM_STATUS_RUNNING) { + length = 0; + } + else if(status.status == SND_PCM_STATUS_OVERRUN) { + artsdebug("Overrun at position: %d" ,status.scount); + if(snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE)<0) + { + arts_info("Overrun: capture prepare error!"); + return -1; + } + length = 0; + } + else { + arts_info("Unknown capture error!"); + return -1; + } + } + else if(length < 0) { + arts_info("Capture error: %s", snd_strerror(length)); + return -1; + } + return length; +} + +int AudioIOALSA::write(void *buffer, int size) +{ + int length; + while((length = snd_pcm_write(m_pcm_handle, buffer, size)) != size) { + if (length == -EINTR) + continue; // Try again + snd_pcm_channel_status_t status; + (void)memset(&status, 0, sizeof(status)); + status.channel = SND_PCM_CHANNEL_PLAYBACK; + + if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { + arts_warning("Playback channel status error!"); + return -1; + } + else if(status.status == SND_PCM_STATUS_UNDERRUN) { + artsdebug("Underrun at position: %d", status.scount); + if(snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK) + < 0) { + arts_warning("Underrun: playback prepare error!"); + return -1; + } + } + else { + arts_warning("Unknown playback error!"); + return -1; + } + } + return size; +} + +int AudioIOALSA::setPcmParams(const int channel) +{ + int &_samplingRate = param(samplingRate); + int &_channels = param(channels); + int &_fragmentSize = param(fragmentSize); + int &_fragmentCount = param(fragmentCount); + + (void)memset(&m_cformat, 0, sizeof(m_cformat)); + m_cformat.interleave = 1; + m_cformat.format = m_format; + m_cformat.rate = _samplingRate; + m_cformat.voices = _channels; + + (void)memset(&m_params, 0, sizeof(m_params)); + switch(m_bufferMode){ + case stream: + m_params.mode=SND_PCM_MODE_STREAM; + break; + case block: + m_params.mode=SND_PCM_MODE_BLOCK; + break; + } + m_params.channel=channel; + (void)memcpy(&m_params.format, &m_cformat, sizeof(m_cformat)); + if(channel==SND_PCM_CHANNEL_CAPTURE){ + m_params.start_mode=SND_PCM_START_GO; + m_params.stop_mode=SND_PCM_STOP_ROLLOVER; + } + else{ //SND_PCM_CHANNEL_PLAYBACK + m_params.start_mode= (m_bufferMode==block) ? SND_PCM_START_FULL : SND_PCM_START_DATA; + m_params.stop_mode=SND_PCM_STOP_ROLLOVER; // SND_PCM_STOP_STOP + //use this ^^^ if you want to track underruns + } + + switch(m_bufferMode){ + case stream: + m_params.buf.stream.queue_size=1024*1024; //_fragmentSize*_fragmentCount; + m_params.buf.stream.fill=SND_PCM_FILL_SILENCE_WHOLE; + m_params.buf.stream.max_fill=1024; + break; + case block: + m_params.buf.block.frag_size=_fragmentSize; + if(channel==SND_PCM_CHANNEL_CAPTURE){ + m_params.buf.block.frags_max=1; + m_params.buf.block.frags_min=1; + } + else{ //SND_PCM_CHANNEL_PLAYBACK + m_params.buf.block.frags_max=_fragmentCount+1; + m_params.buf.block.frags_min=1; + } + } + if(snd_pcm_channel_params(m_pcm_handle, &m_params)<0){ + paramStr(lastError) = "Unable to set channel params!"; + return 1; + } + else { + return 0; + } +} + +void AudioIOALSA::checkCapabilities() +{ + snd_pcm_info_t info; + (void)memset(&info, 0, sizeof(info)); + if(!snd_pcm_info(m_pcm_handle, &info)) { + string flags = ""; + if(info.flags & SND_PCM_INFO_PLAYBACK) flags += "playback "; + if(info.flags & SND_PCM_INFO_CAPTURE) flags += "capture "; + if(info.flags & SND_PCM_INFO_DUPLEX) flags += "duplex "; + if(info.flags & SND_PCM_INFO_DUPLEX_RATE) flags += "duplex_rate "; + artsdebug(" type:%d id:%s\n" + " flags:%s\n" + " playback_subdevices:%d capture_subdevices:%d", + info.type, info.id, + flags.c_str(), + info.playback+1, info.capture+1); + } + else { + arts_warning("Can't get device info!"); //not fatal error + } + + (void)memset(&m_cinfo, 0, sizeof(m_cinfo)); + m_cinfo.channel = SND_PCM_CHANNEL_PLAYBACK; + if(!snd_pcm_channel_info(m_pcm_handle, &m_cinfo)) { + string flags = ""; + if(m_cinfo.flags & SND_PCM_CHNINFO_MMAP) flags += "mmap "; + if(m_cinfo.flags & SND_PCM_CHNINFO_STREAM) flags += "stream "; + if(m_cinfo.flags & SND_PCM_CHNINFO_BLOCK) flags += "block "; + if(m_cinfo.flags & SND_PCM_CHNINFO_BATCH) flags += "batch "; + if(m_cinfo.flags & SND_PCM_CHNINFO_INTERLEAVE) flags += "interleave "; + if(m_cinfo.flags & SND_PCM_CHNINFO_NONINTERLEAVE) flags += "noninterleave "; + if(m_cinfo.flags & SND_PCM_CHNINFO_BLOCK_TRANSFER) flags += "block_transfer "; + if(m_cinfo.flags & SND_PCM_CHNINFO_OVERRANGE) flags += "overrange "; + if(m_cinfo.flags & SND_PCM_CHNINFO_MMAP_VALID) flags += "mmap_valid "; + if(m_cinfo.flags & SND_PCM_CHNINFO_PAUSE) flags += "pause "; + + artsdebug(" subdevice:%d\n" + " flags:%s\n" + " min_rate:%d max_rate:%d\n" + " buffer_size:%d min_fragment_size:%d max_fragment_size:%d\n" + " fragment_align:%d fifo_size:%d transfer_block_size:%d\n" + " mmap_size:%d", + m_cinfo.subdevice, + flags.c_str(), + m_cinfo.min_rate, m_cinfo.max_rate, + m_cinfo.buffer_size, m_cinfo.min_fragment_size, m_cinfo.max_fragment_size, + m_cinfo.fragment_align, m_cinfo.fifo_size, m_cinfo.transfer_block_size, + m_cinfo.mmap_size); + } + else { + arts_warning("Can't get channel info!"); //not fatal error + } +} + +#endif /* HAVE_LIBASOUND */ diff --git a/flow/audioioalsa9.cc b/flow/audioioalsa9.cc new file mode 100644 index 0000000..8367da6 --- /dev/null +++ b/flow/audioioalsa9.cc @@ -0,0 +1,590 @@ + /* + + Copyright (C) 2001 Takashi Iwai + Copyright (C) 2004 Allan Sandfeld Jensen + + based on audioalsa.cc: + Copyright (C) 2000,2001 Jozef Kosoru + jozef.kosoru@pobox.sk + (C) 2000,2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/** + * only compile 'alsa' AudioIO class if configure thinks it is a good idea + */ +#ifdef HAVE_LIBASOUND2 + +#ifdef HAVE_ALSA_ASOUNDLIB_H +#include +#elif defined(HAVE_SYS_ASOUNDLIB_H) +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "audioio.h" +#include "audiosubsys.h" +#include "dispatcher.h" +#include "iomanager.h" + +namespace Arts { + +class AudioIOALSA : public AudioIO, public IONotify { +protected: + // List of file descriptors + struct poll_descriptors { + poll_descriptors() : nfds(0), pfds(0) {}; + int nfds; + struct pollfd *pfds; + } audio_write_pds, audio_read_pds; + + snd_pcm_t *m_pcm_playback; + snd_pcm_t *m_pcm_capture; + snd_pcm_format_t m_format; + int m_period_size, m_periods; + + void startIO(); + int setPcmParams(snd_pcm_t *pcm); + static int poll2iomanager(int pollTypes); + static int iomanager2poll(int ioTypes); + void getDescriptors(snd_pcm_t *pcm, poll_descriptors *pds); + void watchDescriptors(poll_descriptors *pds); + + void notifyIO(int fd, int types); + + int xrun(snd_pcm_t *pcm); +#ifdef HAVE_SND_PCM_RESUME + int resume(snd_pcm_t *pcm); +#endif + +public: + AudioIOALSA(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOALSA,"alsa","Advanced Linux Sound Architecture"); +} + +using namespace std; +using namespace Arts; + +AudioIOALSA::AudioIOALSA() +{ + param(samplingRate) = 44100; + paramStr(deviceName) = "default"; // ALSA pcm device name - not file name + param(fragmentSize) = 1024; + param(fragmentCount) = 7; + param(channels) = 2; + param(direction) = directionWrite; + param(format) = 16; + /* + * default parameters + */ + m_format = SND_PCM_FORMAT_S16_LE; + m_pcm_playback = NULL; + m_pcm_capture = NULL; +} + +bool AudioIOALSA::open() +{ + string& _error = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _direction = param(direction); + int& _format = param(format); + + m_pcm_playback = NULL; + m_pcm_capture = NULL; + + /* initialize format */ + switch(_format) { + case 16: // 16bit, signed little endian + m_format = SND_PCM_FORMAT_S16_LE; + break; + case 17: // 16bit, signed big endian + m_format = SND_PCM_FORMAT_S16_BE; + break; + case 8: // 8bit, unsigned + m_format = SND_PCM_FORMAT_U8; + break; + default: // test later + m_format = SND_PCM_FORMAT_UNKNOWN; + break; + } + + /* open pcm device */ + int err; + if (_direction & directionWrite) { + if ((err = snd_pcm_open(&m_pcm_playback, _deviceName.c_str(), + SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { + _error = "device: "; + _error += _deviceName.c_str(); + _error += " can't be opened for playback ("; + _error += snd_strerror(err); + _error += ")"; + return false; + } + snd_pcm_nonblock(m_pcm_playback, 0); + } + if (_direction & directionRead) { + if ((err = snd_pcm_open(&m_pcm_capture, _deviceName.c_str(), + SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { + _error = "device: "; + _error += _deviceName.c_str(); + _error += " can't be opened for capture ("; + _error += snd_strerror(err); + _error += ")"; + snd_pcm_close(m_pcm_playback); + return false; + } + snd_pcm_nonblock(m_pcm_capture, 0); + } + + artsdebug("ALSA driver: %s", _deviceName.c_str()); + + /* check device capabilities */ + // checkCapabilities(); + + /* set PCM communication parameters */ + if (((_direction & directionWrite) && setPcmParams(m_pcm_playback)) || + ((_direction & directionRead) && setPcmParams(m_pcm_capture))) { + snd_pcm_close(m_pcm_playback); + snd_pcm_close(m_pcm_capture); + return false; + } + + artsdebug("buffering: %d fragments with %d bytes " + "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, + (float)(_fragmentSize*_fragmentCount) / + (float)(2.0 * _samplingRate * _channels)*1000.0); + + + startIO(); + /* restore the format value */ + switch (m_format) { + case SND_PCM_FORMAT_S16_LE: + _format = 16; + break; + case SND_PCM_FORMAT_S16_BE: + _format = 17; + break; + case SND_PCM_FORMAT_U8: + _format = 8; + break; + default: + _error = "Unknown PCM format"; + return false; + } + + /* start recording */ + if (_direction & directionRead) + snd_pcm_start(m_pcm_capture); + + return true; +} + +void AudioIOALSA::close() +{ + arts_debug("Closing ALSA-driver"); + int& _direction = param(direction); + if ((_direction & directionRead) && m_pcm_capture) { + (void)snd_pcm_drop(m_pcm_capture); + (void)snd_pcm_close(m_pcm_capture); + m_pcm_capture = NULL; + } + if ((_direction & directionWrite) && m_pcm_playback) { + (void)snd_pcm_drop(m_pcm_playback); + (void)snd_pcm_close(m_pcm_playback); + m_pcm_playback = NULL; + } + Dispatcher::the()->ioManager()->remove(this, IOType::all); + + delete[] audio_read_pds.pfds; + delete[] audio_write_pds.pfds; + audio_read_pds.pfds = NULL; audio_write_pds.pfds = NULL; + audio_read_pds.nfds = 0; audio_write_pds.nfds = 0; +} + +void AudioIOALSA::setParam(AudioParam p, int& value) +{ + param(p) = value; + if (m_pcm_playback != NULL) { + setPcmParams(m_pcm_playback); + } + if (m_pcm_capture != NULL) { + setPcmParams(m_pcm_capture); + } +} + +int AudioIOALSA::getParam(AudioParam p) +{ + snd_pcm_sframes_t avail; + switch(p) { + + case canRead: + if (! m_pcm_capture) return -1; + while ((avail = snd_pcm_avail_update(m_pcm_capture)) < 0) { + if (avail == -EPIPE) + avail = xrun(m_pcm_capture); +#ifdef HAVE_SND_PCM_RESUME + else if (avail == -ESTRPIPE) + avail = resume(m_pcm_capture); +#endif + if (avail < 0) { + arts_info("Capture error: %s", snd_strerror(avail)); + return -1; + } + } + return snd_pcm_frames_to_bytes(m_pcm_capture, avail); + + case canWrite: + if (! m_pcm_playback) return -1; + while ((avail = snd_pcm_avail_update(m_pcm_playback)) < 0) { + if (avail == -EPIPE) + avail = xrun(m_pcm_playback); +#ifdef HAVE_SND_PCM_RESUME + else if (avail == -ESTRPIPE) + avail = resume(m_pcm_playback); +#endif + if (avail < 0) { + arts_info("Playback error: %s", snd_strerror(avail)); + return -1; + } + } + return snd_pcm_frames_to_bytes(m_pcm_playback, avail); + + case selectReadFD: + return -1; + + case selectWriteFD: + return -1; + + case autoDetect: + { + /* + * that the ALSA driver could be compiled doesn't say anything + * about whether it will work (the user might be using an OSS + * kernel driver). + * If we can open the device, it'll work - and we'll have to use + * a higher number than OSS to avoid buggy OSS emulation being used. + */ + int card = -1; + if (snd_card_next(&card) < 0 || card < 0) { + // No ALSA drivers in use... + return 0; + } + return 15; + } + + default: + return param(p); + } +} + +void AudioIOALSA::startIO() +{ + /* get & watch PCM file descriptor(s) */ + if (m_pcm_playback) { + getDescriptors(m_pcm_playback, &audio_write_pds); + watchDescriptors(&audio_write_pds); + } + if (m_pcm_capture) { + getDescriptors(m_pcm_capture, &audio_read_pds); + watchDescriptors(&audio_read_pds); + } + +} + +int AudioIOALSA::poll2iomanager(int pollTypes) +{ + int types = 0; + + if(pollTypes & POLLIN) + types |= IOType::read; + if(pollTypes & POLLOUT) + types |= IOType::write; + if(pollTypes & POLLERR) + types |= IOType::except; + + return types; +} + +int AudioIOALSA::iomanager2poll(int ioTypes) +{ + int types = 0; + + if(ioTypes & IOType::read) + types |= POLLIN; + if(ioTypes & IOType::write) + types |= POLLOUT; + if(ioTypes & IOType::except) + types |= POLLERR; + + return types; +} + +void AudioIOALSA::getDescriptors(snd_pcm_t *pcm, poll_descriptors *pds) +{ + pds->nfds = snd_pcm_poll_descriptors_count(pcm); + pds->pfds = new struct pollfd[pds->nfds]; + + if (snd_pcm_poll_descriptors(pcm, pds->pfds, pds->nfds) != pds->nfds) { + arts_info("Cannot get poll descriptor(s)\n"); + } + +} + +void AudioIOALSA::watchDescriptors(poll_descriptors *pds) +{ + for(int i=0; infds; i++) { + // Check in which direction this handle is supposed to be watched + int types = poll2iomanager(pds->pfds[i].events); + Dispatcher::the()->ioManager()->watchFD(pds->pfds[i].fd, types, this); + } +} + +int AudioIOALSA::xrun(snd_pcm_t *pcm) +{ + int err; + artsdebug("xrun!!\n"); + if ((err = snd_pcm_prepare(pcm)) < 0) + return err; + if (pcm == m_pcm_capture) + snd_pcm_start(pcm); // ignore error here.. + return 0; +} + +#ifdef HAVE_SND_PCM_RESUME +int AudioIOALSA::resume(snd_pcm_t *pcm) +{ + int err; + artsdebug("resume!\n"); + while ((err = snd_pcm_resume(pcm)) == -EAGAIN) + sleep(1); /* wait until suspend flag is not released */ + if (err < 0) { + if ((err = snd_pcm_prepare(pcm)) < 0) + return err; + if (pcm == m_pcm_capture) + snd_pcm_start(pcm); // ignore error here.. + } + return 0; +} +#endif + +int AudioIOALSA::read(void *buffer, int size) +{ + int frames = snd_pcm_bytes_to_frames(m_pcm_capture, size); + int length; + while ((length = snd_pcm_readi(m_pcm_capture, buffer, frames)) < 0) { + if (length == -EINTR) + continue; // Try again + else if (length == -EPIPE) + length = xrun(m_pcm_capture); +#ifdef HAVE_SND_PCM_RESUME + else if (length == -ESTRPIPE) + length = resume(m_pcm_capture); +#endif + if (length < 0) { + arts_info("Capture error: %s", snd_strerror(length)); + return -1; + } + } + return snd_pcm_frames_to_bytes(m_pcm_capture, length); +} + +int AudioIOALSA::write(void *buffer, int size) +{ + int frames = snd_pcm_bytes_to_frames(m_pcm_playback, size); + int length; + while ((length = snd_pcm_writei(m_pcm_playback, buffer, frames)) < 0) { + if (length == -EINTR) + continue; // Try again + else if (length == -EPIPE) + length = xrun(m_pcm_playback); +#ifdef HAVE_SND_PCM_RESUME + else if (length == -ESTRPIPE) + length = resume(m_pcm_playback); +#endif + if (length < 0) { + arts_info("Playback error: %s", snd_strerror(length)); + return -1; + } + } + + // Start the sink if it needs it + if (snd_pcm_state( m_pcm_playback ) == SND_PCM_STATE_PREPARED) + snd_pcm_start(m_pcm_playback); + + if (length == frames) // Sometimes the fragments are "odd" in alsa + return size; + else + return snd_pcm_frames_to_bytes(m_pcm_playback, length); +} + +void AudioIOALSA::notifyIO(int fd, int type) +{ + int todo = 0; + + // Translate from iomanager-types to poll-types, + // inorder to fake a snd_pcm_poll_descriptors_revents call. + if(m_pcm_playback) { + for(int i=0; i < audio_write_pds.nfds; i++) { + if(fd == audio_write_pds.pfds[i].fd) { + audio_write_pds.pfds[i].revents = iomanager2poll(type); + todo |= AudioSubSystem::ioWrite; + } + } + if (todo & AudioSubSystem::ioWrite) { + unsigned short revents; + snd_pcm_poll_descriptors_revents(m_pcm_playback, + audio_write_pds.pfds, + audio_write_pds.nfds, + &revents); + if (! (revents & POLLOUT)) todo &= ~AudioSubSystem::ioWrite; + } + } + if(m_pcm_capture) { + for(int i=0; i < audio_read_pds.nfds; i++) { + if(fd == audio_read_pds.pfds[i].fd) { + audio_read_pds.pfds[i].revents = iomanager2poll(type); + todo |= AudioSubSystem::ioRead; + } + } + if (todo & AudioSubSystem::ioRead) { + unsigned short revents; + snd_pcm_poll_descriptors_revents(m_pcm_capture, + audio_read_pds.pfds, + audio_read_pds.nfds, + &revents); + if (! (revents & POLLIN)) todo &= ~AudioSubSystem::ioRead; + } + } + + if (type & IOType::except) todo |= AudioSubSystem::ioExcept; + + if (todo != 0) AudioSubSystem::the()->handleIO(todo); +} + +int AudioIOALSA::setPcmParams(snd_pcm_t *pcm) +{ + int &_samplingRate = param(samplingRate); + int &_channels = param(channels); + int &_fragmentSize = param(fragmentSize); + int &_fragmentCount = param(fragmentCount); + string& _error = paramStr(lastError); + + snd_pcm_hw_params_t *hw; + snd_pcm_hw_params_alloca(&hw); + snd_pcm_hw_params_any(pcm, hw); + + if (snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { + _error = "Unable to set interleaved!"; + return 1; + } + if (m_format == SND_PCM_FORMAT_UNKNOWN) { + // test the available formats + // try 16bit first, then fall back to 8bit + if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_S16_LE)) + m_format = SND_PCM_FORMAT_S16_LE; + else if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_S16_BE)) + m_format = SND_PCM_FORMAT_S16_BE; + else if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_U8)) + m_format = SND_PCM_FORMAT_U8; + else + m_format = SND_PCM_FORMAT_UNKNOWN; + } + if (snd_pcm_hw_params_set_format(pcm, hw, m_format) < 0) { + _error = "Unable to set format!"; + return 1; + } + + unsigned int rate = snd_pcm_hw_params_set_rate_near(pcm, hw, _samplingRate, 0); + const unsigned int tolerance = _samplingRate/10+1000; + if (abs((int)rate - (int)_samplingRate) > (int)tolerance) { + _error = "Can't set requested sampling rate!"; + char details[80]; + sprintf(details," (requested rate %d, got rate %d)", + _samplingRate, rate); + _error += details; + return 1; + } + _samplingRate = rate; + + if (snd_pcm_hw_params_set_channels(pcm, hw, _channels) < 0) { + _error = "Unable to set channels!"; + return 1; + } + + m_period_size = _fragmentSize; + if (m_format != SND_PCM_FORMAT_U8) + m_period_size <<= 1; + if (_channels > 1) + m_period_size /= _channels; + if ((m_period_size = snd_pcm_hw_params_set_period_size_near(pcm, hw, m_period_size, 0)) < 0) { + _error = "Unable to set period size!"; + return 1; + } + m_periods = _fragmentCount; + if ((m_periods = snd_pcm_hw_params_set_periods_near(pcm, hw, m_periods, 0)) < 0) { + _error = "Unable to set periods!"; + return 1; + } + + if (snd_pcm_hw_params(pcm, hw) < 0) { + _error = "Unable to set hw params!"; + return 1; + } + + _fragmentSize = m_period_size; + _fragmentCount = m_periods; + if (m_format != SND_PCM_FORMAT_U8) + _fragmentSize >>= 1; + if (_channels > 1) + _fragmentSize *= _channels; + + return 0; // ok, we're ready.. +} + +#endif /* HAVE_LIBASOUND2 */ diff --git a/flow/audioiocsl.cc b/flow/audioiocsl.cc new file mode 100644 index 0000000..9a9b44e --- /dev/null +++ b/flow/audioiocsl.cc @@ -0,0 +1,640 @@ + /* + + Copyright (C) 2000-2002 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/** + * only compile 'csl' AudioIO class if libcsl is present + */ +#ifdef HAVE_LIBCSL +#include + +/* g_newa */ +#include + +#include + +#include "audioio.h" +#include "audiosubsys.h" +#include "debug.h" +#include "dispatcher.h" +#include "iomanager.h" + +namespace Arts { + +class AudioIOCSL : public AudioIO, + public IONotify +{ +protected: + CslPcmStream *inputStream, *outputStream; + CslDriver *cslDriver; + int requestedFragmentSize; + int requestedFragmentCount; + const char *cslDriverName; + + std::vector cslFds, cslOldFds; + int csl2iomanager(int cslTypes); + void updateFds(); + + void notifyIO(int fd, int types); + static void handleRead(void *user_data, CslPcmStream *stream); + static void handleWrite(void *user_data, CslPcmStream *stream); + +public: + AudioIOCSL(const char *driverName = 0); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOCSL,"csl","Common Sound Layer"); + +class AudioIOCSLFactory : public AudioIOFactory { +protected: + const char *driverName; + std::string _name; + std::string _fullName; + +public: + AudioIOCSLFactory(const char *driverName) + : driverName(driverName) + { + _name = "csl-"; + _name += driverName; + + _fullName = "Common Sound Layer ("; + _fullName += driverName; + _fullName += ")"; + } + virtual ~AudioIOCSLFactory() + { + } + AudioIO *createAudioIO() { return new AudioIOCSL(driverName); } + virtual const char *name() { return _name.c_str(); } + virtual const char *fullName() { return _fullName.c_str(); } +}; + +static class AudioIOCSLInit { +protected: + std::list factories; + +public: + AudioIOCSLInit() + { + unsigned int i,n; + const char **drivers = csl_list_drivers(&n); + + for(i = 0; i < n; i++) + factories.push_back(new AudioIOCSLFactory(drivers[i])); + } + ~AudioIOCSLInit() + { + std::list::iterator i; + for(i = factories.begin(); i != factories.end(); i++) + delete (*i); + + factories.clear(); + } +} aci; + +}; + +using namespace std; +using namespace Arts; + +AudioIOCSL::AudioIOCSL(const char *driverName) + : cslDriverName(driverName) +{ + /* + * default parameters + */ + param(samplingRate) = 44100; + paramStr(deviceName) = "todo"; + requestedFragmentSize = param(fragmentSize) = 1024; + requestedFragmentCount = param(fragmentCount) = 7; + param(channels) = 2; + param(direction) = 2; + +#ifdef WORDS_BIGENDIAN + param(format) = 17; +#else + param(format) = 16; +#endif +} + +bool AudioIOCSL::open() +{ + string& errorMsg = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _format = param(format); + int fmt = 0; + char *env = 0; + + if(cslDriverName && strcmp(cslDriverName, "arts") == 0) + env = arts_strdup_printf("ARTS_SERVER=%s",_deviceName.c_str()); + + if(env) + { + putenv(env); + arts_debug("AudioIOCsl: set %s\n",env); + } + + CslErrorType error; + error = csl_driver_init(cslDriverName, &cslDriver); /* choose backend */ + + if(env) + { + putenv("ARTS_SERVER"); + free(env); + } + + if (error) + { + errorMsg = "unable to initialize CSL driver: "; + errorMsg += csl_strerror(error); + return false; + } + + if(_format == 8) + fmt = CSL_PCM_FORMAT_U8; + else if(_format == 16) + fmt = CSL_PCM_FORMAT_S16_LE; + else if(_format == 17) + fmt = CSL_PCM_FORMAT_S16_BE; + + inputStream = outputStream = 0; + if(param(direction) & directionRead) + { + /* open PCM output stream */ + error = csl_pcm_open_output(cslDriver, + "artsd output", + _samplingRate, + _channels, + fmt, &inputStream); + if (error) + { + errorMsg = "failed to open CSL input stream: "; + errorMsg += csl_strerror(error); + return false; + } + csl_pcm_set_callback(inputStream, handleRead, 0, 0); + } + if(param(direction) & directionWrite) + { + /* open PCM output stream */ + error = csl_pcm_open_output(cslDriver, + "artsd output", + _samplingRate, + _channels, + fmt, &outputStream); + if (error) + { + close(); + + errorMsg = "failed to open CSL output stream: "; + errorMsg += csl_strerror(error); + return false; + } + csl_pcm_set_callback(outputStream, handleWrite, 0, 0); + } +#if 0 + if (_format && (ossBits(gotFormat) != ossBits(requestedFormat))) + { + char details[80]; + sprintf(details," (_format = %d, asked driver to give %d, got %d)", + _format, requestedFormat, gotFormat); + + _error = "Can't set playback format"; + _error += details; + + close(); + return false; + } + + if(gotFormat == AFMT_U8) + _format = 8; + else if(gotFormat == AFMT_S16_LE) + _format = 16; + else if(gotFormat == AFMT_S16_BE) + _format = 17; + else + { + char details[80]; + sprintf(details," (_format = %d, asked driver to give %d, got %d)", + _format, requestedFormat, gotFormat); + + _error = "unknown format given by driver"; + _error += details; + + close(); + return false; + } + + + int stereo=-1; /* 0=mono, 1=stereo */ + + if(_channels == 1) + { + stereo = 0; + } + if(_channels == 2) + { + stereo = 1; + } + + if(stereo == -1) + { + _error = "internal error; set channels to 1 (mono) or 2 (stereo)"; + + close(); + return false; + } + + int requeststereo = stereo; + + if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1) + { + _error = "SNDCTL_DSP_STEREO failed - "; + _error += strerror(errno); + + close(); + return false; + } + + if (requeststereo != stereo) + { + _error = "audio device doesn't support number of requested channels"; + + close(); + return false; + } + + int speed = _samplingRate; + + if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1) + { + _error = "SNDCTL_DSP_SPEED failed - "; + _error += strerror(errno); + + close(); + return false; + } + + /* + * Some soundcards seem to be able to only supply "nearly" the requested + * sampling rate, especially PAS 16 cards seem to quite radical supplying + * something different than the requested sampling rate ;) + * + * So we have a quite large tolerance here (when requesting 44100 Hz, it + * will accept anything between 38690 Hz and 49510 Hz). Most parts of the + * aRts code will do resampling where appropriate, so it shouldn't affect + * sound quality. + */ + int tolerance = _samplingRate/10+1000; + + if (abs(speed-_samplingRate) > tolerance) + { + _error = "can't set requested samplingrate"; + + char details[80]; + sprintf(details," (requested rate %d, got rate %d)", + _samplingRate, speed); + _error += details; + + close(); + return false; + } + _samplingRate = speed; + + /* + * set the fragment settings to what the user requested + */ + + _fragmentSize = requestedFragmentSize; + _fragmentCount = requestedFragmentCount; + + /* + * lower 16 bits are the fragment size (as 2^S) + * higher 16 bits are the number of fragments + */ + int frag_arg = 0; + + int size = _fragmentSize; + while(size > 1) { size /= 2; frag_arg++; } + frag_arg += (_fragmentCount << 16); + if(ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_arg) == -1) + { + char buffer[1024]; + _error = "can't set requested fragments settings"; + sprintf(buffer,"size%d:count%d\n",_fragmentSize,_fragmentCount); + close(); + return false; + } + + /* + * now see what we really got as cards aren't required to supply what + * we asked for + */ + audio_buf_info info; + if(ioctl(audio_fd,SNDCTL_DSP_GETOSPACE, &info) == -1) + { + _error = "can't retrieve fragment settings"; + close(); + return false; + } + + // update fragment settings with what we got + _fragmentSize = info.fragsize; + _fragmentCount = info.fragstotal; + + artsdebug("buffering: %d fragments with %d bytes " + "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, + (float)(_fragmentSize*_fragmentCount) / + (float)(2.0 * _samplingRate * _channels)*1000.0); + + /* + * Workaround for broken kernel drivers: usually filling up the audio + * buffer is _only_ required if _fullDuplex is true. However, there + * are kernel drivers around (especially everything related to ES1370/1371) + * which will not trigger select()ing the file descriptor unless we have + * written something first. + */ + char *zbuffer = (char *)calloc(sizeof(char), _fragmentSize); + if(_format == 8) + for(int zpos = 0; zpos < _fragmentSize; zpos++) + zbuffer[zpos] |= 0x80; + + for(int fill = 0; fill < _fragmentCount; fill++) + { + int len = ::write(audio_fd,zbuffer,_fragmentSize); + if(len != _fragmentSize) + { + arts_debug("AudioIOCSL: failed prefilling audio buffer (might cause synchronization problems in conjunction with full duplex)"); + fill = _fragmentCount+1; + } + } + free(zbuffer); + + /* + * Triggering - the original aRts code did this for full duplex: + * + * - stop audio i/o using SETTRIGGER(~(PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT)) + * - fill buffer (see zbuffer code two lines above) + * - start audio i/o using SETTRIGGER(PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT) + * + * this should guarantee synchronous start of input/output. Today, it + * seems there are too many broken drivers around for this. + */ + + if(device_caps & DSP_CAP_TRIGGER) + { + int enable_bits = 0; + + if(param(direction) & 1) enable_bits |= PCM_ENABLE_INPUT; + if(param(direction) & 2) enable_bits |= PCM_ENABLE_OUTPUT; + + if(ioctl(audio_fd,SNDCTL_DSP_SETTRIGGER, &enable_bits) == -1) + { + _error = "can't start sound i/o"; + + close(); + return false; + } + } +#endif + updateFds(); + return true; +} + +void AudioIOCSL::close() +{ + if(inputStream) + { + csl_pcm_close(inputStream); + inputStream = 0; + } + if(outputStream) + { + csl_pcm_close(outputStream); + outputStream = 0; + } + updateFds(); +} + +void AudioIOCSL::setParam(AudioParam p, int& value) +{ + switch(p) + { + case fragmentSize: + param(p) = requestedFragmentSize = value; + break; + case fragmentCount: + param(p) = requestedFragmentCount = value; + break; + default: + param(p) = value; + break; + } +} + +int AudioIOCSL::getParam(AudioParam p) +{ + CslErrorType error; + CslPcmStatus status; + + switch(p) + { + case canRead: + error = csl_pcm_get_status (inputStream, &status); + if (error) /* FIXME */ + arts_fatal("unable to obtain csl stream status: %s", + csl_strerror (error)); + + updateFds(); + return status.n_bytes_available; + break; + + case canWrite: + error = csl_pcm_get_status(outputStream, &status); + if (error) /* FIXME */ + arts_fatal("unable to obtain csl stream status: %s", + csl_strerror (error)); + + updateFds(); + return status.n_bytes_available; + break; + + case autoDetect: + /* CSL is pretty experimental currently */ + return 1; + break; + + default: + return param(p); + break; + } +} + +int AudioIOCSL::read(void *buffer, int size) +{ + arts_assert(inputStream != 0); + + int result = csl_pcm_read(inputStream, size, buffer); + updateFds(); + + return result; +} + +void AudioIOCSL::handleRead(void *, CslPcmStream *) +{ + AudioSubSystem::the()->handleIO(AudioSubSystem::ioRead); +} + +int AudioIOCSL::write(void *buffer, int size) +{ + arts_assert(outputStream != 0); + + int result = csl_pcm_write(outputStream, size, buffer); + updateFds(); + + return result; +} + +void AudioIOCSL::handleWrite(void *, CslPcmStream *) +{ + AudioSubSystem::the()->handleIO(AudioSubSystem::ioWrite); +} + +/* mainloop integration: make CSL callbacks work inside the aRts mainloop */ + +int AudioIOCSL::csl2iomanager(int cslTypes) +{ + /* FIXME: doublecheck this list */ + int types = 0; + + if(cslTypes & CSL_POLLIN) + types |= IOType::read; + if(cslTypes & CSL_POLLOUT) + types |= IOType::write; + if(cslTypes & CSL_POLLERR) + types |= IOType::except; + + return types; +} + +void AudioIOCSL::updateFds() +{ + unsigned int n_fds = csl_poll_count_fds(cslDriver); + CslPollFD *newFds = g_newa(CslPollFD, n_fds); + + unsigned int have_fds = csl_poll_get_fds(cslDriver, n_fds, newFds); + arts_assert(have_fds == n_fds); + + cslFds.clear(); + + unsigned int i; + for(i = 0; i < have_fds; i++) + cslFds.push_back(newFds[i]); + + /* FIXME: if csl provided a flag for this, we could save some work here */ + bool fdsChanged; + if(cslFds.size() == cslOldFds.size()) + { + fdsChanged = false; + for(i = 0; i < have_fds; i++) + { + if(cslFds[i].events != cslOldFds[i].events) + fdsChanged = true; + if(cslFds[i].fd != cslOldFds[i].fd) + fdsChanged = true; + } + } + else + { + fdsChanged = true; + } + if(!fdsChanged) + return; + + vector::iterator ci; + + /* remove old watches */ + /* + * UGLY! due to broken API, we can only remove all watches here, and not + * do anything selectively - its not a problem for the code here, but it + * might be a problem elsewhere. Unfortunately, it can't be fixed without + * breaking BC. + */ + Dispatcher::the()->ioManager()->remove(this, IOType::all); + arts_debug("AudioIOCSL::updateFds(): removing watches"); + + /* add new watches */ + for(ci = cslFds.begin(); ci < cslFds.end(); ci++) + { + int types = csl2iomanager(ci->events); + if(types) + { + Dispatcher::the()->ioManager()->watchFD(ci->fd, types, this); + arts_debug("AudioIOCSL::updateFds(): adding watch on %d", ci->fd); + } + } + + cslOldFds = cslFds; +} + +void AudioIOCSL::notifyIO(int fd, int type) +{ + vector::iterator fi; + + for(fi = cslFds.begin(); fi != cslFds.end(); fi++) + { + if(fi->fd == fd) + { + int ftype = csl2iomanager(fi->events); + fi->revents = 0; + + if(type & ftype & IOType::read) + fi->revents |= CSL_POLLIN; + if(type & ftype & IOType::write) + fi->revents |= CSL_POLLOUT; + if(type & ftype & IOType::except) + fi->revents |= CSL_POLLERR; + + if(fi->revents) + csl_poll_handle_fds(cslDriver, 1, &(*fi)); + } + } + updateFds(); +} + +#endif diff --git a/flow/audioioesd.cc b/flow/audioioesd.cc new file mode 100644 index 0000000..a3fa4b5 --- /dev/null +++ b/flow/audioioesd.cc @@ -0,0 +1,231 @@ + /* + + Copyright (C) 2001 Jochen Hoenicke + jochen@gnu.org + + Copyright (C) 2003 Ian Chiew + ian@snork.net + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/** + * only compile esound AudioIO class if libesd was detected during + * configure + */ +#ifdef HAVE_LIBESD + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "audioio.h" +#include "audiosubsys.h" +#include "iomanager.h" +#include "dispatcher.h" + +#include + +#ifdef __BIG_ENDIAN__ +#define _format_bits 17 +#else +#define _format_bits 16 +#endif + +namespace Arts { + +class AudioIOESD : public AudioIO, public IONotify { +protected: + int server_fd, read_fd, write_fd; + +public: + AudioIOESD(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + void notifyIO(int fd, int type); + + bool open(); + void close(); + void run(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOESD,"esd","Enlightened Sound Daemon"); +} + +using namespace std; +using namespace Arts; + +AudioIOESD::AudioIOESD() +{ + /* + * default parameters + */ + param(samplingRate) = 44100; + paramStr(deviceName) = "null"; + param(fragmentSize) = 1024; + param(fragmentCount) = 7; + param(format) = _format_bits; + param(channels) = 2; + param(direction) = 2; + + server_fd = -1; + read_fd = -1; + write_fd = -1; +} + +bool AudioIOESD::open() +{ + int& _channels = param(channels); + int& _direction = param(direction); + int& _samplingRate = param(samplingRate); + int& _format = param(format); + string& _error = paramStr(lastError); + + if ((server_fd = esd_open_sound(NULL)) == -1) + { + _error = "Couldn't connect to server"; + return false; + } + + esd_server_info_t *server_info = esd_get_server_info(server_fd); + + if (server_info == NULL) + { + _error = "Unable to query EsounD server"; + return false; + } + + esd_format_t server_format = server_info->format; + + _samplingRate = server_info->rate; + _channels = (server_format & ESD_STEREO) ? 2 : 1; + _format = (server_format & ESD_BITS16) ? _format_bits : 8; + + esd_free_server_info(server_info); + + if (_direction & directionRead) + { + read_fd = esd_record_stream(server_format, _samplingRate, + NULL, "aRts"); + if (read_fd == -1) + { + _error = "Couldn't create read uflow"; + return false; + } + } + + if (_direction & directionWrite) + { + write_fd = esd_play_stream(server_format, _samplingRate, + NULL, "aRts"); + if (write_fd == -1) + { + _error = "Couldn't create write flow"; + return false; + } + } + + return true; +} + +void AudioIOESD::notifyIO(int, int) +{ +} + +void AudioIOESD::close() +{ + if (write_fd != -1) + esd_close(write_fd); + + if (read_fd != -1) + esd_close(read_fd); + + if (server_fd != -1) + esd_close(server_fd); +} + +void AudioIOESD::setParam(AudioParam p, int& value) +{ + switch(p) + { + case channels: + case format: + case direction: + case samplingRate: + param(p) = value; + close(); + open(); + return; + + default: + param(p) = value; + return; + } +} + +int AudioIOESD::getParam(AudioParam p) +{ + switch(p) + { + case selectReadFD: + return read_fd; + + case selectWriteFD: + return write_fd; + + case canRead: + return ESD_BUF_SIZE; + + case canWrite: + return ESD_BUF_SIZE; + + // ESD handles are actually socket descriptors, and I know not + // of any portable way to peek at the socket's send or receive + // buffers. + + default: + return param(p); + } +} + +int AudioIOESD::read(void *buffer, int size) +{ + return ::read(read_fd, buffer, size); +} + +int AudioIOESD::write(void *buffer, int size) +{ + return ::write(write_fd, buffer, size); +} + +#endif diff --git a/flow/audioiojack.cc b/flow/audioiojack.cc new file mode 100644 index 0000000..787ac03 --- /dev/null +++ b/flow/audioiojack.cc @@ -0,0 +1,346 @@ +/* + Copyright (C) 2004 Matthias Kretz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_LIBJACK + +#include +#include + +#include "debug.h" +#include "audioio.h" +#include "audiosubsys.h" +#include "iomanager.h" +#include "dispatcher.h" + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#undef DEBUG_WAVEFORM +#ifdef DEBUG_WAVEFORM +#include +#endif + +#include +#include + +namespace Arts { + +class AudioIOJack : public AudioIO, public TimeNotify { +private: +#ifdef DEBUG_WAVEFORM + std::ofstream plotfile; +#endif + char * processBuffer; + size_t buffersize; + +protected: + jack_client_t *jack; + jack_port_t *outleft, *outright; + jack_port_t *inleft, *inright; + jack_ringbuffer_t *olb, *orb, *ilb, *irb; + +public: + AudioIOJack(); + + void notifyTime(); + + void setParam( AudioParam p, int & val ); + int getParam(AudioParam param); + + static int jackCallback( jack_nframes_t, void * ); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOJack,"jack","Jack Audio Connection Kit"); +} + +using namespace std; +using namespace Arts; + +AudioIOJack::AudioIOJack() + : +#ifdef DEBUG_WAVEFORM + plotfile( "/dev/shm/audioiojack.plot" ), +#endif + jack( 0 ) + , outleft( 0 ) + , outright( 0 ) + , inleft( 0 ) + , inright( 0 ) +{ + /* + * default parameters + */ + param( samplingRate ) = 44100; + paramStr( deviceName ) = "jack"; + param( fragmentSize ) = 512; + param( fragmentCount ) = 2; + param( channels ) = 2; + param( direction ) = 2; + param( format ) = 32; +} + +bool AudioIOJack::open() +{ + string& _error = paramStr( lastError ); + jack = jack_client_new( "artsd" ); + if( jack == 0 ) + { + _error = "Couldn't connect to jackd"; + return false; + } + + int& _sampleRate = param(samplingRate); + _sampleRate = jack_get_sample_rate( jack ); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + + /* + * don't allow unreasonable large fragmentSize/Count combinations, + * because "real" hardware also doesn't + */ + + if(_fragmentSize > 1024*8) _fragmentSize = 1024*8; + + while(_fragmentSize * _fragmentCount > 1024*128) + _fragmentCount--; + + jack_set_process_callback( jack, Arts::AudioIOJack::jackCallback, this ); + + if( param( direction ) & directionWrite ) + { + outleft = jack_port_register( jack, "out_1", + JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); + outright = jack_port_register( jack, "out_2", + JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); + olb = jack_ringbuffer_create( + sizeof( jack_default_audio_sample_t ) * + _fragmentSize * _fragmentCount ); + orb = jack_ringbuffer_create( + sizeof( jack_default_audio_sample_t ) * + _fragmentSize * _fragmentCount ); + } + if( param( direction ) & directionRead ) + { + inleft = jack_port_register( jack, "in_1", + JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); + inright = jack_port_register( jack, "in_2", + JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); + ilb = jack_ringbuffer_create( + sizeof( jack_default_audio_sample_t ) * + 1024 * 64 ); + irb = jack_ringbuffer_create( + sizeof( jack_default_audio_sample_t ) * + 1024 * 64 ); + } + + if( jack_activate( jack ) ) + { + _error = "Activating as jack client failed."; + return false; + } + + const char **ports; + if( param( direction ) & directionRead ) + { + ports = jack_get_ports( jack, 0, 0, JackPortIsPhysical + | JackPortIsOutput ); + if( ports == 0 ) + { + arts_warning( "Cannot find any capture ports to" + " connect to. You need to manually connect" + " the capture ports in jack" ); + } + else + { + if( ports[ 0 ] != 0 ) + jack_connect( jack, ports[ 0 ], + jack_port_name( inleft ) ); + if( ports[ 1 ] != 0 ) + jack_connect( jack, ports[ 1 ], + jack_port_name( inright ) ); + free( ports ); + } + } + if( param( direction ) & directionWrite ) + { + ports = jack_get_ports( jack, 0, 0, JackPortIsPhysical + | JackPortIsInput ); + if( ports == 0 ) + { + arts_warning( "Cannot find any playback ports to" + " connect to. You need to manually connect" + " the playback ports in jack" ); + } + else + { + if( ports[ 0 ] != 0 ) + jack_connect( jack, jack_port_name( outleft ), + ports[ 0 ] ); + if( ports[ 1 ] != 0 ) + jack_connect( jack, jack_port_name( outright ), + ports[ 1 ] ); + free( ports ); + } + } + + // Install the timer + Dispatcher::the()->ioManager()->addTimer(10, this); + + return true; +} + +void AudioIOJack::close() +{ + jack_client_close( jack ); + Dispatcher::the()->ioManager()->removeTimer(this); +} + +int AudioIOJack::jackCallback( jack_nframes_t nframes, void * args ) +{ + AudioIOJack * that = static_cast( args ); + + that->buffersize = nframes * sizeof( jack_default_audio_sample_t ); + if( that->outleft ) + { + if( jack_ringbuffer_read_space( that->olb ) < that->buffersize ) + { + that->processBuffer = static_cast( + jack_port_get_buffer( that->outleft, nframes ) ); + memset( that->processBuffer, 0, that->buffersize ); + that->processBuffer = static_cast( + jack_port_get_buffer( that->outright, nframes ) ); + memset( that->processBuffer, 0, that->buffersize ); + } + else + { + that->processBuffer = static_cast( + jack_port_get_buffer( that->outleft, nframes ) ); + jack_ringbuffer_read( that->olb, that->processBuffer, that->buffersize ); + that->processBuffer = static_cast( + jack_port_get_buffer( that->outright, nframes ) ); + jack_ringbuffer_read( that->orb, that->processBuffer, that->buffersize ); + } + } + if( that->inleft ) + { + that->processBuffer = static_cast( + jack_port_get_buffer( that->inleft, nframes ) ); + jack_ringbuffer_write( that->ilb, that->processBuffer, that->buffersize ); + that->processBuffer = static_cast( + jack_port_get_buffer( that->inright, nframes ) ); + jack_ringbuffer_write( that->irb, that->processBuffer, that->buffersize ); + } + return 0; +} + +void AudioIOJack::setParam( AudioParam p, int& val ) +{ + // don't change the format - jack only supports 32 bit float + if( p == format ) + return; + AudioIO::setParam( p, val ); +} + +int AudioIOJack::getParam(AudioParam p) +{ + switch(p) + { + case canRead: + return MIN( jack_ringbuffer_read_space( ilb ), jack_ringbuffer_read_space( irb ) ) * param( channels ); + case canWrite: + return MIN( jack_ringbuffer_write_space( olb ), jack_ringbuffer_write_space( orb ) ) * param( channels ); + default: + return AudioIO::getParam( p ); + } +} + +int AudioIOJack::read(void *buffer, int size) +{ + float * floatbuffer = static_cast( buffer ); + if( param( channels ) == 2 ) + { + float * end = ( float * )( static_cast( buffer ) + size ); + while( floatbuffer < end ) + { + jack_ringbuffer_read( ilb, ( char* )( floatbuffer++ ), sizeof( float ) ); +#ifdef DEBUG_WAVEFORM + plotfile << *( floatbuffer - 1 ) << "\n"; +#endif + jack_ringbuffer_read( irb, ( char* )( floatbuffer++ ), sizeof( float ) ); + } + } + else if( param( channels ) == 1 ) + { + jack_ringbuffer_read( ilb, ( char* )( floatbuffer ), size ); + } + return size; +} + +int AudioIOJack::write(void *buffer, int size) +{ + float * floatbuffer = static_cast( buffer ); + if( param( channels ) == 2 ) + { + float * end = ( float * )( static_cast( buffer ) + size ); + while( floatbuffer < end ) + { + jack_ringbuffer_write( olb, ( char* )( floatbuffer++ ), sizeof( float ) ); + jack_ringbuffer_write( orb, ( char* )( floatbuffer++ ), sizeof( float ) ); + } + } + else if( param( channels ) == 1 ) + { + jack_ringbuffer_write( olb, ( char* )( floatbuffer ), size ); + } + return size; +} + +void AudioIOJack::notifyTime() +{ + int& _direction = param(direction); + int& _fragmentSize = param(fragmentSize); + + for( ;; ) + { + int todo = 0; + if( ( _direction & directionRead ) && ( getParam( canRead ) >= _fragmentSize ) ) + todo |= AudioSubSystem::ioRead; + + if( ( _direction & directionWrite ) && ( getParam( canWrite ) >= _fragmentSize ) ) + todo |= AudioSubSystem::ioWrite; + + if( ! todo ) + return; + + AudioSubSystem::the()->handleIO( todo ); + } +} + +#endif +// vim: sw=4 ts=4 diff --git a/flow/audioiolibaudioio.cc b/flow/audioiolibaudioio.cc new file mode 100644 index 0000000..e7c545e --- /dev/null +++ b/flow/audioiolibaudioio.cc @@ -0,0 +1,236 @@ + /* + + Copyright (C) 2001 Robert Lunnon + bob@yarrabee.net.au + Copyright (C) 2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/** + * only compile 'LibAudioIO' AudioIO class if libaudio was detected during + * configure + */ +#ifdef HAVE_LIBAUDIOIO + +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SELECT_H +#include // Needed on some systems. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "audioio.h" + +namespace Arts { + +class AudioIOLibAudioIO : public AudioIO { +protected: + int audio_fd; + int requestedFragmentSize; + int requestedFragmentCount; + SampleSpec_t spec; + +public: + AudioIOLibAudioIO(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOLibAudioIO,"libaudioio"," Portable Audio Library"); +}; + +using namespace std; +using namespace Arts; + +AudioIOLibAudioIO::AudioIOLibAudioIO() +{ + /* + * default parameters + */ + param(samplingRate) = spec.rate=44100; + paramStr(deviceName) = "/dev/Audio"; + requestedFragmentSize = param(fragmentSize) = 4096; + requestedFragmentCount =spec.max_blocks= param(fragmentCount) = 7; + param(channels) = spec.channels=2; + param(direction) = 2; +} + +bool AudioIOLibAudioIO::open() +{ + string& _error = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _format = param(format); + + int mode; + spec.channels=_channels; + spec.max_blocks= param(fragmentCount); + spec.rate= _samplingRate; + spec.encoding= ENCODE_PCM; + spec.precision=16 ; + spec.endian=ENDIAN_NATURAL; + spec.disable_threads=1; + + if(param(direction) == 3) + mode = O_RDWR|O_NDELAY; + else if(param(direction) == 2) + mode = O_WRONLY|O_NDELAY; + else + { + _error = "invalid direction"; + return false; + } + + audio_fd = ::AudioIOOpenX( mode, &spec,&spec ); + if(audio_fd == -1) + { + _error = "device "; + _error += _deviceName.c_str(); + _error += " can't be opened ("; + _error += strerror(errno); + _error += ")"; + return false; + } + + + /* + * since we use spec.endian=ENDIAN_NATURAL we'll have little endian audio + * on little endian machines and big endian audio on big endian machines: + */ +#ifdef WORDS_BIGENDIAN + _format = 17; +#else + _format = 16; +#endif + + spec.channels=_channels; + + spec.rate = _samplingRate; + + + _fragmentSize = requestedFragmentSize; + spec.max_blocks=_fragmentCount = requestedFragmentCount; + + + artsdebug("buffering: %d fragments with %d bytes " + "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, + (float)(_fragmentSize*_fragmentCount) / + (float)(2.0 * _samplingRate * _channels)*1000.0); + + return(true); +} + +void AudioIOLibAudioIO::close() +{ + ::AudioIOClose(); +} + +void AudioIOLibAudioIO::setParam(AudioParam p, int& value) +{ + switch(p) + { + case fragmentSize: + param(p) = requestedFragmentSize = value; + break; + case fragmentCount: + param(p) = requestedFragmentCount = value; + break; + default: + param(p) = value; + break; + } +} + +int AudioIOLibAudioIO::getParam(AudioParam p) +{ + switch(p) + { + case canRead: + return AudioIOCheckRead(); + break; + + case canWrite: + return (AudioIOCheckWriteReady()) ? (16*1024) : 0; + // Assume if writable can write 16K + // Arts Really doesn't care + break; + + case selectReadFD: + return (param(direction) & directionRead)?audio_fd:-1; + break; + + case selectWriteFD: + return (param(direction) & directionWrite)?audio_fd:-1; + break; + + case autoDetect: + /* + * if there is a "native" aRts driver, we'll rather use this + * than the generic libaudioio one, because the native one + * is likely to be better optimized to the needs of aRts than + * a generic driver, so keep the value small + */ + return 3; + break; + + default: + return param(p); + break; + } +} + +int AudioIOLibAudioIO::read(void *buffer, int size) +{ + arts_assert(audio_fd != 0); + return ::AudioIORead(buffer,size); +} + +int AudioIOLibAudioIO::write(void *buffer, int size) +{ + arts_assert(audio_fd != 0); + return ::AudioIOWrite(buffer,size); +} + +#endif diff --git a/flow/audioiomas.cc b/flow/audioiomas.cc new file mode 100644 index 0000000..e49fec2 --- /dev/null +++ b/flow/audioiomas.cc @@ -0,0 +1,619 @@ + /* + + Copyright (C) 2001-2003 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* + * Only compile this AudioIO class if we have MAS + */ +#ifdef HAVE_LIBMAS + +extern "C" { +#include +#include +#include +} + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "audioio.h" +#include "audiosubsys.h" +#include "iomanager.h" +#include "dispatcher.h" + +namespace Arts { + + class AudioIOMAS : public AudioIO, public TimeNotify { + protected: + mas_channel_t audio_channel; + mas_port_t mix_sink; + mas_port_t srate_source, srate_sink; + mas_port_t audio_source, audio_sink; + mas_port_t endian_sink, endian_source; + mas_port_t sbuf_source, sbuf_sink; + mas_port_t squant_sink, squant_source; + mas_port_t open_source; /* (!) */ + mas_device_t endian; + mas_device_t srate; + mas_device_t squant; + mas_device_t sbuf; + mas_data *data; + mas_package package; + int32 mas_error; + + std::list allocated_channels; + std::list allocated_ports; + std::list allocated_devices; + + double lastUpdate, bytesPerSec; + int readBufferAvailable; + int writeBufferAvailable; + + double currentTime(); + void updateBufferSizes(); + +#ifdef WORDS_BIGENDIAN + static const int defaultFormat = 17; +#else + static const int defaultFormat = 16; +#endif + bool close_with_error(const std::string& text); + public: + AudioIOMAS(); + + // Timer callback + void notifyTime(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); + }; + + REGISTER_AUDIO_IO(AudioIOMAS,"mas","MAS Audio Input/Output"); + +}; + +using namespace std; +using namespace Arts; + +AudioIOMAS::AudioIOMAS() +{ + /* + * default parameters + */ + param(samplingRate) = 44100; + paramStr(deviceName) = ""; // TODO + param(fragmentSize) = 4096; + param(fragmentCount) = 7; + param(channels) = 2; + param(direction) = 2; + param(format) = defaultFormat; +} + +namespace { + int masInitCount = 0; +} + +// Opens the audio device +bool AudioIOMAS::open() +{ + string& _error = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _format = param(format); + + /* FIXME: do we need to free what we allocate with mas_init() in close() */ + if (!masInitCount) + { + mas_error = mas_init(); + + if (mas_error < 0) + return close_with_error("error connecting to MAS server"); + } + masInitCount++; + + if (param(direction) != 2) + { + _error = "unsupported direction (currently no full duplex support)"; + return false; + } + + /* + * data path + * + * audio_sink + * audio_channel: data_channel ("artsd") + * audio_source + * | + * V + * endian_sink + * endian: instantiate_device ("endian") + * open_source = endian_source + * | + * V + * [squant_sink] + * [squant] + * [squant_source] + * | + * V + * [srate_sink] + * [srate] + * [srate_source] + * | + * V + * sbuf_sink + * sbuf + * sbuf_source + * | + * V + * mix_sink: port ("default_mix_sink") + */ + + // audio_channel, source & sink + mas_error = mas_make_data_channel("artsd", &audio_channel, &audio_source, &audio_sink); + if (mas_error < 0) + return close_with_error("error initializing MAS data channel"); + + allocated_channels.push_back(audio_channel); + allocated_ports.push_back(audio_source); + allocated_ports.push_back(audio_sink); + + // endian, source & sink + mas_error = mas_asm_instantiate_device( "endian", 0, 0, &endian ); + if ( mas_error < 0 ) + return close_with_error("error initantiating MAS endian device"); + + allocated_devices.push_back(endian); + + mas_error = mas_asm_get_port_by_name( endian, "sink", &endian_sink ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS endian device sink port"); + + allocated_ports.push_back(endian_sink); + + mas_error = mas_asm_get_port_by_name( endian, "source", &endian_source ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS endian device source port"); + + allocated_ports.push_back(endian_source); + + char ratestring[16], resolutionstring[16]; + sprintf (ratestring, "%u", _samplingRate); + sprintf (resolutionstring, "%u", _format); + + mas_data_characteristic* dc; + + dc = (mas_data_characteristic *)MAS_NEW( dc ); + masc_setup_dc( dc, 6 ); + masc_append_dc_key_value( dc, "format", (_format==8) ? "ulinear":"linear" ); + + masc_append_dc_key_value( dc, "resolution", resolutionstring ); + masc_append_dc_key_value( dc, "sampling rate", ratestring ); + masc_append_dc_key_value( dc, "channels", "2" ); + masc_append_dc_key_value( dc, "endian", "little" ); + + mas_error = mas_asm_connect_source_sink( audio_source, endian_sink, dc ); + if ( mas_error < 0 ) + return close_with_error("error connecting MAS net audio source to endian sink"); + + /* The next device is 'if needed' only. After the following if() + statement, open_source will contain the current unconnected + source in the path (will be either endian_source or + squant_source in this case) + */ + open_source = endian_source; + + if ( _format != 16 ) + { + arts_debug("MAS output: Sample resolution is not 16 bit/sample, instantiating squant device."); + + // squant, source & sink + mas_error = mas_asm_instantiate_device( "squant", 0, 0, &squant ); + if ( mas_error < 0 ) + return close_with_error("error creating MAS squant device"); + + allocated_devices.push_back(squant); + + mas_error = mas_asm_get_port_by_name( squant, "sink", &squant_sink ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS squant device sink port"); + + allocated_ports.push_back(squant_sink); + + mas_error = mas_asm_get_port_by_name( squant, "source", &squant_source ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS squant device source port"); + + allocated_ports.push_back(squant_source); + + arts_debug( "MAS output: Connecting endian -> squant."); + + masc_strike_dc( dc ); + masc_setup_dc( dc, 6 ); + masc_append_dc_key_value( dc,"format",(_format==8) ? "ulinear":"linear" ); + masc_append_dc_key_value( dc, "resolution", resolutionstring ); + masc_append_dc_key_value( dc, "sampling rate", ratestring ); + masc_append_dc_key_value( dc, "channels", "2" ); + masc_append_dc_key_value( dc, "endian", "host" ); + + mas_error = mas_asm_connect_source_sink( endian_source, squant_sink, dc ); + if ( mas_error < 0 ) + return close_with_error("error connecting MAS endian output to squant device"); + + /* sneaky: the squant device is optional -> pretend it isn't there */ + open_source = squant_source; + } + + + /* Another 'if necessary' device, as above */ + if ( _samplingRate != 44100 ) + { + arts_debug ("MAS output: Sample rate is not 44100, instantiating srate device."); + + // srate, source & sink + mas_error = mas_asm_instantiate_device( "srate", 0, 0, &srate ); + if ( mas_error < 0 ) + return close_with_error("error initantiating MAS srate device"); + + allocated_devices.push_back(srate); + + mas_error = mas_asm_get_port_by_name( srate, "sink", &srate_sink ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS srate sink port"); + + allocated_ports.push_back(srate_sink); + + mas_error = mas_asm_get_port_by_name( srate, "source", &srate_source ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS srate source port"); + + allocated_ports.push_back(srate_source); + + arts_debug( "MAS output: Connecting to srate."); + + masc_strike_dc( dc ); + masc_setup_dc( dc, 6 ); + masc_append_dc_key_value( dc, "format", "linear" ); + masc_append_dc_key_value( dc, "resolution", "16" ); + masc_append_dc_key_value( dc, "sampling rate", ratestring ); + masc_append_dc_key_value( dc, "channels", "2" ); + masc_append_dc_key_value( dc, "endian", "host" ); + + mas_error = mas_asm_connect_source_sink( open_source, srate_sink, dc ); + if ( mas_error < 0 ) + return close_with_error("error connecting to MAS srate device"); + + open_source = srate_source; + } + + // sbuf, source & sink + mas_error = mas_asm_instantiate_device( "sbuf", 0, 0, &sbuf ); + if ( mas_error < 0 ) + return close_with_error("error initantiating MAS sbuf device"); + + allocated_devices.push_back(sbuf); + + mas_error = mas_asm_get_port_by_name( sbuf, "sink", &sbuf_sink ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS sbuf device sink port"); + + allocated_ports.push_back(sbuf_sink); + + mas_error = mas_asm_get_port_by_name( sbuf, "source", &sbuf_source ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS sbuf device source port"); + + allocated_ports.push_back(sbuf_source); + + masc_strike_dc( dc ); + masc_setup_dc( dc, 6 ); + + masc_append_dc_key_value( dc, "format", "linear" ); + masc_append_dc_key_value( dc, "resolution", "16" ); + masc_append_dc_key_value( dc, "sampling rate", "44100" ); + masc_append_dc_key_value( dc, "channels", "2" ); + masc_append_dc_key_value( dc, "endian", "host" ); + + arts_debug("MAS output: Connecting to sbuf."); + + mas_error = mas_asm_connect_source_sink( open_source, sbuf_sink, dc ); + if ( mas_error < 0 ) + return close_with_error("error connecting to MAS mixer device"); + + /* configure sbuf */ + + float BUFTIME_MS = _fragmentSize * _fragmentCount; + BUFTIME_MS *= 1000.0; + BUFTIME_MS /= (float)_channels; + if (_format > 8) + BUFTIME_MS /= 2.0; + BUFTIME_MS /= (float)_samplingRate; + + arts_debug("MAS output: BUFTIME_MS = %f", BUFTIME_MS); + + masc_setup_package( &package, NULL, 0, 0 ); + masc_pushk_uint32( &package, "buftime_ms", (uint32) BUFTIME_MS ); + masc_finalize_package( &package ); + mas_set( sbuf, "buftime_ms", &package ); + masc_strike_package( &package ); + + masc_setup_package( &package, NULL, 0, 0 ); + masc_pushk_int32( &package, "mc_clkid", 9 ); + masc_finalize_package( &package ); + mas_set( sbuf, "mc_clkid", &package ); + masc_strike_package( &package ); + + mas_source_play( sbuf ); + + // mix_sink + mas_error = mas_asm_get_port_by_name( 0, "default_mix_sink", &mix_sink ); + if (mas_error < 0) + return close_with_error("error finding MAS default sink"); + + allocated_ports.push_back(mix_sink); + + arts_debug("MAS output: Connecting sbuf to mix_sink."); + + mas_error = mas_asm_connect_source_sink( sbuf_source, mix_sink, dc ); + if ( mas_error < 0 ) + return close_with_error("error connecting to MAS mixer device"); + + data = (mas_data *)MAS_NEW( data ); + masc_setup_data( data, _fragmentSize ); /* we can reuse this */ + data->length = _fragmentSize; + data->allocated_length = data->length; + data->header.type = 10; + + arts_debug("MAS output: playing."); + + // Install the timer + Dispatcher::the()->ioManager()->addTimer(10, this); + + bytesPerSec = _channels * _samplingRate; + if (_format > 8) + bytesPerSec *= 2; + + lastUpdate = 0; + + return true; +} + +double AudioIOMAS::currentTime() +{ + timeval tv; + gettimeofday(&tv,0); + + return (double)tv.tv_sec + (double)tv.tv_usec/1000000.0; +} + +bool AudioIOMAS::close_with_error(const string& text) +{ + string& error = paramStr(lastError); + error = text; + error += masc_strmerror (mas_error); + return false; +} + +void AudioIOMAS::close() +{ + list::iterator pi; + for (pi = allocated_ports.begin(); pi != allocated_ports.end(); pi++) + mas_free_port (*pi); + allocated_ports.clear(); + + list::iterator ci; + for (ci = allocated_channels.begin(); ci != allocated_channels.end(); ci++) + mas_free_channel (*ci); + allocated_channels.clear(); + + list::iterator di; + for (di = allocated_devices.begin(); di != allocated_devices.end(); di++) + { + mas_device_t device = *di; + mas_error = mas_asm_terminate_device_instance(device, 0); + if (mas_error < 0) + arts_warning ("MAS output: error while closing device: %s", masc_strmerror(mas_error)); + + mas_free_device(device); + } + allocated_devices.clear(); + + Dispatcher::the()->ioManager()->removeTimer(this); +} + +void AudioIOMAS::updateBufferSizes() +{ + double time = currentTime(); + double waterMark = param(fragmentSize); + waterMark *= 1.3; + + if ((time - lastUpdate) * bytesPerSec < waterMark) + return; + + lastUpdate = time; + + uint32 inbuf_ms; + int32 mas_error; + + mas_error = mas_get( sbuf, "inbuf_ms", 0 , &package ); + if ( mas_error < 0 ) + arts_fatal ("MAS output: error getting size of buffer: %s", masc_strmerror(mas_error)); + + masc_pull_uint32( &package, &inbuf_ms ); + masc_strike_package( &package ); + + //arts_debug(" inbuf_ms = %u", inbuf_ms); + + float bytes = inbuf_ms; + bytes /= 1000.0; + bytes *= param(samplingRate); + bytes *= param(channels); + if(param(format) > 8) + bytes *= 2; + + int bytesFree = param(fragmentSize) * param(fragmentCount) - (int)bytes; + + if (bytesFree < param(fragmentSize)) + bytesFree = 0; + + writeBufferAvailable = bytesFree; + + arts_debug ("MAS output buffer: %6d / %6d bytes used => %6d bytes free", + (int)bytes, param(fragmentSize) * param(fragmentCount), writeBufferAvailable); +} + +// This is called on each timer tick +void AudioIOMAS::notifyTime() +{ + updateBufferSizes(); + + int& _direction = param(direction); + int& _fragmentSize = param(fragmentSize); + + for (;;) { + int todo = 0; + + if ((_direction & directionRead) && (getParam(canRead) >= _fragmentSize)) + todo |= AudioSubSystem::ioRead; + + if ((_direction & directionWrite) && (getParam(canWrite) >= _fragmentSize)) + todo |= AudioSubSystem::ioWrite; + + if (!todo) + return; + + AudioSubSystem::the()->handleIO(todo); + } +} + +void AudioIOMAS::setParam(AudioParam p, int& value) +{ + switch(p) { +#if 0 + case fragmentSize: + param(p) = requestedFragmentSize = value; + break; + case fragmentCount: + param(p) = requestedFragmentCount = value; + break; +#endif + default: + param(p) = value; + break; + } +} + +int AudioIOMAS::getParam(AudioParam p) +{ + int bytes; + int count; + + switch(p) + { +#if 0 + case canRead: + if (ioctl(audio_fd, AUDIO_GETINFO, &auinfo) < 0) + return (0); + bytes = (auinfo.record.samples * bytesPerSample) - bytesRead; + if (bytes < 0) { + printf("Error: bytes %d < 0, samples=%u, bytesRead=%u\n", + bytes, auinfo.record.samples, bytesRead); + bytes = 0; + } + return bytes; + + case canWrite: + if (ioctl(audio_fd, AUDIO_GETINFO, &auinfo) < 0) + return (0); + count = SUN_MAX_BUFFER_SIZE - + (bytesWritten - (auinfo.play.samples * bytesPerSample)); + return count; +#endif + case canWrite: + return writeBufferAvailable; + + case autoDetect: + /* + * Fairly small priority, for we haven't tested this a lot + */ + return 3; + + default: + return param(p); + } +} + +int AudioIOMAS::read(void *buffer, int size) +{ +#if 0 + size = ::read(audio_fd, buffer, size); + if (size < 0) + return 0; + + bytesRead += size; + return size; +#endif + return 0; +} + +int AudioIOMAS::write(void *buffer, int size) +{ + static int ts = 0; + static int seq = 0; + data->header.sequence = seq++; + data->header.media_timestamp = ts; + ts += size / 4; + + assert(size == data->length); + memcpy(data->segment, buffer, size); + + int32 mas_error = mas_send( audio_channel , data ); + if (mas_error < 0) + arts_fatal ("MAS output: problem during mas_send: %s", masc_strmerror(mas_error)); + + writeBufferAvailable -= size; + return size; +} + +#endif /* HAVE_LIBMAS */ diff --git a/flow/audioionas.cc b/flow/audioionas.cc new file mode 100644 index 0000000..3106ade --- /dev/null +++ b/flow/audioionas.cc @@ -0,0 +1,260 @@ + /* + + Copyright (C) 2001 Jochen Hoenicke + jochen@gnu.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/** + * only compile nas AudioIO class if libaudio was detected during + * configure + */ +#ifdef HAVE_LIBAUDIONAS + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "audioio.h" +#include "audiosubsys.h" +#include "iomanager.h" +#include "dispatcher.h" + +#include