initial import from racket-sound -> racket-audio
This commit is contained in:
@@ -0,0 +1,486 @@
|
||||
(module libmpg123-ffi racket/base
|
||||
|
||||
(require ffi/unsafe
|
||||
ffi/unsafe/define
|
||||
"private/utils.rkt"
|
||||
)
|
||||
|
||||
(provide mpg123-ffi-decoder-handler
|
||||
)
|
||||
|
||||
|
||||
;(define lib (ffi-lib "/home/hans/tmp/lib/libmpg123.so")) ;(get-lib '("libmpg123") '("0" #f)))
|
||||
(define lib (get-lib '("libmpg123") '("0" #f)))
|
||||
(define-ffi-definer define-libmpg123 lib
|
||||
#:default-make-fail make-not-available)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Some MPG123 Constants
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define _size_t _size)
|
||||
|
||||
(define SEEK_SET 0)
|
||||
(define SEEK_CUR 1)
|
||||
(define SEEK_END 2)
|
||||
|
||||
(define _Seek_t
|
||||
(_enum '(seek-set = 0
|
||||
seek-cur = 1
|
||||
seek-end = 2
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
(define _MPG123_Result
|
||||
(_enum '(MPG123_DONE = -12 ;/**< Message: Track ended. Stop decoding. */
|
||||
MPG123_NEW_FORMAT = -11 ;/**< Message: Output format will be different on next call.
|
||||
; Note that some libmpg123 versions between 1.4.3 and 1.8.0
|
||||
; insist on you calling mpg123_getformat() after getting this
|
||||
; message code. Newer verisons behave like advertised:
|
||||
; You have the chance to call mpg123_getformat(), but you can
|
||||
; also just continue decoding and get your data. */
|
||||
MPG123_NEED_MORE = -10 ;/**< Message: For feed reader: "Feed me more!" (call
|
||||
; mpg123_feed() or mpg123_decode() with some new input data). */
|
||||
MPG123_ERR = -1 ;/**< Generic Error */
|
||||
MPG123_OK = 0 ;/**< Success */
|
||||
MPG123_BAD_OUTFORMAT ;/**< Unable to set up output format! */
|
||||
MPG123_BAD_CHANNEL ;/**< Invalid channel number specified. */
|
||||
MPG123_BAD_RATE ;/**< Invalid sample rate specified. */
|
||||
MPG123_ERR_16TO8TABLE ;/**< Unable to allocate memory for 16 to 8 converter table! */
|
||||
MPG123_BAD_PARAM ;/**< Bad parameter id! */
|
||||
MPG123_BAD_BUFFER ;/**< Bad buffer given -- invalid pointer or too small size. */
|
||||
MPG123_OUT_OF_MEM ;/**< Out of memory -- some malloc() failed. */
|
||||
MPG123_NOT_INITIALIZED ;/**< You didn't initialize the library! */
|
||||
MPG123_BAD_DECODER ;/**< Invalid decoder choice. */
|
||||
MPG123_BAD_HANDLE ;/**< Invalid mpg123 handle. */
|
||||
MPG123_NO_BUFFERS ;/**< Unable to initialize frame buffers (out of memory?). */
|
||||
MPG123_BAD_RVA ;/**< Invalid RVA mode. */
|
||||
MPG123_NO_GAPLESS ;/**< This build doesn't support gapless decoding. */
|
||||
MPG123_NO_SPACE ;/**< Not enough buffer space. */
|
||||
MPG123_BAD_TYPES ;/**< Incompatible numeric data types. */
|
||||
MPG123_BAD_BAND ;/**< Bad equalizer band. */
|
||||
MPG123_ERR_NULL ;/**< Null pointer given where valid storage address needed. */
|
||||
MPG123_ERR_READER ;/**< Error reading the stream. */
|
||||
MPG123_NO_SEEK_FROM_END ;/**< Cannot seek from end (end is not known). */
|
||||
MPG123_BAD_WHENCE ;/**< Invalid 'whence' for seek function.*/
|
||||
MPG123_NO_TIMEOUT ;/**< Build does not support stream timeouts. */
|
||||
MPG123_BAD_FILE ;/**< File access error. */
|
||||
MPG123_NO_SEEK ;/**< Seek not supported by stream. */
|
||||
MPG123_NO_READER ;/**< No stream opened or no reader callback setup. */
|
||||
MPG123_BAD_PARS ;/**< Bad parameter handle. */
|
||||
MPG123_BAD_INDEX_PAR ;/**< Bad parameters to MPG123_index() and MPG123_set_index() */
|
||||
MPG123_OUT_OF_SYNC ;/**< Lost track in bytestream and did not try to resync. */
|
||||
MPG123_RESYNC_FAIL ;/**< Resync failed to find valid MPEG data. */
|
||||
MPG123_NO_8BIT ;/**< No 8bit encoding possible. */
|
||||
MPG123_BAD_ALIGN ;/**< Stack aligmnent error */
|
||||
MPG123_NULL_BUFFER ;/**< NULL input buffer with non-zero size... */
|
||||
MPG123_NO_RELSEEK ;/**< Relative seek not possible (screwed up file offset) */
|
||||
MPG123_NULL_POINTER ;/**< You gave a null pointer somewhere where you shouldn't have. */
|
||||
MPG123_BAD_KEY ;/**< Bad key value given. */
|
||||
MPG123_NO_INDEX ;/**< No frame index in this build. */
|
||||
MPG123_INDEX_FAIL ;/**< Something with frame index went wrong. */
|
||||
MPG123_BAD_DECODER_SETUP ;/**< Something prevents a proper decoder setup */
|
||||
MPG123_MISSING_FEATURE ;/**< This feature has not been built into libmpg123. */
|
||||
MPG123_BAD_VALUE ;/**< A bad value has been given somewhere. */
|
||||
MPG123_LSEEK_FAILED ;/**< Low-level seek failed. */
|
||||
MPG123_BAD_CUSTOM_IO ;/**< Custom I/O not prepared. */
|
||||
MPG123_LFS_OVERFLOW ;/**< Offset value overflow during translation
|
||||
; of large file API calls -- your client program
|
||||
; cannot handle that large file. */
|
||||
MPG123_INT_OVERFLOW ;/**< Some integer overflow. */
|
||||
MPG123_BAD_FLOAT ;/**< Floating-point computations work not as expected. */
|
||||
)
|
||||
_int
|
||||
)
|
||||
)
|
||||
|
||||
(define _mpg123_param
|
||||
(_enum '(force-mono = #x7
|
||||
mono-left = #x1
|
||||
mono-right = #x2
|
||||
mono-mix = #x4
|
||||
force-stereo = #x8
|
||||
force-8bit = #x10
|
||||
quiet = #x20
|
||||
gapless = #x40
|
||||
no-resync = #x80
|
||||
seekbuffer = #x100
|
||||
fuzzy = #x200
|
||||
force-float = #x400
|
||||
plain-id3text = #x800
|
||||
ignore-streamlength = #x1000
|
||||
skip-id3v2 = #x2000
|
||||
ignore-infoframe = #x4000
|
||||
auto-resample = #x8000
|
||||
)
|
||||
_int
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
#|
|
||||
/** Flag bits for MPG123_FLAGS, use the usual binary or to combine. */
|
||||
enum mpg123_param_flags
|
||||
|
||||
MPG123_FORCE_MONO = 0x7 /**< 0111 Force some mono mode: This is a test bitmask for seeing if any mono forcing is active. */
|
||||
,MPG123_MONO_LEFT = 0x1 /**< 0001 Force playback of left channel only. */
|
||||
,MPG123_MONO_RIGHT = 0x2 /**< 0010 Force playback of right channel only. */
|
||||
,MPG123_MONO_MIX = 0x4 /**< 0100 Force playback of mixed mono. */
|
||||
,MPG123_FORCE_STEREO = 0x8 /**< 1000 Force stereo output. */
|
||||
,MPG123_FORCE_8BIT = 0x10 /**< 00010000 Force 8bit formats. */
|
||||
,MPG123_QUIET = 0x20 /**< 00100000 Suppress any printouts (overrules verbose). */
|
||||
,MPG123_GAPLESS = 0x40 /**< 01000000 Enable gapless decoding (default on if libmpg123 has support). */
|
||||
,MPG123_NO_RESYNC = 0x80 /**< 10000000 Disable resync stream after error. */
|
||||
,MPG123_SEEKBUFFER = 0x100 /**< 000100000000 Enable small buffer on non-seekable streams to allow some peek-ahead (for better MPEG sync). */
|
||||
,MPG123_FUZZY = 0x200 /**< 001000000000 Enable fuzzy seeks (guessing byte offsets or using approximate seek points from Xing TOC) */
|
||||
,MPG123_FORCE_FLOAT = 0x400 /**< 010000000000 Force floating point output (32 or 64 bits depends on mpg123 internal precision). */
|
||||
,MPG123_PLAIN_ID3TEXT = 0x800 /**< 100000000000 Do not translate ID3 text data to UTF-8. ID3 strings will contain the raw text data, with the first byte containing the ID3 encoding code. */
|
||||
,MPG123_IGNORE_STREAMLENGTH = 0x1000 /**< 1000000000000 Ignore any stream length information contained in the stream, which can be contained in a 'TLEN' frame of an ID3v2 tag or a Xing tag */
|
||||
,MPG123_SKIP_ID3V2 = 0x2000 /**< 10 0000 0000 0000 Do not parse ID3v2 tags, just skip them. */
|
||||
,MPG123_IGNORE_INFOFRAME = 0x4000 /**< 100 0000 0000 0000 Do not parse the LAME/Xing info frame, treat it as normal MPEG data. */
|
||||
,MPG123_AUTO_RESAMPLE = 0x8000 /**< 1000 0000 0000 0000 Allow automatic internal resampling of any kind (default on if supported). Especially when going lowlevel with replacing output buffer, you might want to unset this flag. Setting MPG123_DOWNSAMPLE or MPG123_FORCE_RATE will override this. */
|
||||
|#
|
||||
|
||||
(define _mpg123_handle _pointer)
|
||||
|
||||
|
||||
; MPG123_EXPORT int mpg123_init (void)
|
||||
; Not relevant anymore
|
||||
(define-libmpg123 mpg123_init
|
||||
(_fun -> _MPG123_Result))
|
||||
|
||||
; MPG123_EXPORT mpg123_handle *mpg123_new (const char *decoder, int *error)
|
||||
(define-libmpg123 mpg123_new
|
||||
(_fun _string/utf-8 (err : (_ptr o _int))
|
||||
-> (h : _mpg123_handle)
|
||||
-> (values h err)))
|
||||
|
||||
; MPG123_EXPORT size_t mpg123_outblock ( mpg123_handle * mh )
|
||||
(define-libmpg123 mpg123_outblock
|
||||
(_fun _mpg123_handle -> _size_t))
|
||||
|
||||
; MPG123_EXPORT int mpg123_open (mpg123_handle *mh, const char *path)
|
||||
(define-libmpg123 mpg123_open
|
||||
(_fun _mpg123_handle _string/utf-8 -> _MPG123_Result))
|
||||
|
||||
; MPG123_EXPORT int mpg123_close (mpg123_handle *mh)
|
||||
(define-libmpg123 mpg123_close
|
||||
(_fun _mpg123_handle -> _MPG123_Result))
|
||||
|
||||
; MPG123_EXPORT int mpg123_getformat (mpg123_handle *mh, long *rate, int *channels, int *encoding)
|
||||
(define-libmpg123 mpg123_getformat
|
||||
(_fun _mpg123_handle
|
||||
(rate : (_ptr o _long))
|
||||
(channels : (_ptr o _int))
|
||||
(encoding : (_ptr o _int))
|
||||
-> (r : _MPG123_Result)
|
||||
-> (values r rate channels encoding)))
|
||||
|
||||
; MPG123_EXPORT int mpg123_encsize ( int encoding )
|
||||
(define-libmpg123 mpg123_encsize
|
||||
(_fun _int -> _int))
|
||||
|
||||
; MPG123_EXPORT int mpg123_read (mpg123_handle *mh, void *outmemory, size_t outmemsize, size_t *done)
|
||||
(define-libmpg123 mpg123_read
|
||||
(_fun _mpg123_handle
|
||||
_pointer
|
||||
_size_t
|
||||
(done : (_ptr o _size_t))
|
||||
-> (r : _MPG123_Result)
|
||||
-> (values r done)))
|
||||
|
||||
; MPG123_EXPORT int64_t mpg123_tell64 ( mpg123_handle * mh )
|
||||
(define-libmpg123 mpg123_tell64
|
||||
(_fun _mpg123_handle -> _int64))
|
||||
|
||||
; MPG123_EXPORT int64_t mpg123_seek64(mpg123_handle * mh, int64_t sampleoff, int whence )
|
||||
(define-libmpg123 mpg123_seek64
|
||||
(_fun _mpg123_handle _int64 _Seek_t -> _int64))
|
||||
|
||||
; MPG123_EXPORT int mpg123_scan ( mpg123_handle * mh )
|
||||
(define-libmpg123 mpg123_scan
|
||||
(_fun _mpg123_handle -> _MPG123_Result))
|
||||
|
||||
; MPG123_EXPORT off_t mpg123_length ( mpg123_handle * mh )
|
||||
(define-libmpg123 mpg123_length64
|
||||
(_fun _mpg123_handle -> _int64))
|
||||
|
||||
; MPG123_EXPORT void mpg123_delete (mpg123_handle *mh)
|
||||
(define-libmpg123 mpg123_delete
|
||||
(_fun _mpg123_handle -> _void))
|
||||
|
||||
; MPG123_EXPORT void mpg123_exit (void)
|
||||
; Not relevant anymore
|
||||
(define-libmpg123 mpg123_exit
|
||||
(_fun -> _void))
|
||||
|
||||
; MPG123_EXPORT const char* mpg123_plain_strerror ( int errcode )
|
||||
(define-libmpg123 mpg123_plain_strerror
|
||||
(_fun _MPG123_Result -> _string*/utf-8))
|
||||
|
||||
(define mpg123_int_strerror
|
||||
(get-ffi-obj "mpg123_plain_strerror"
|
||||
lib
|
||||
(_fun _int -> _string*/utf-8)))
|
||||
|
||||
|
||||
;MPG123_EXPORT int mpg123_getparam ( mpg123_handle * mh,;
|
||||
; enum mpg123_parms type,
|
||||
; long * value,
|
||||
; double * fvalue
|
||||
; )
|
||||
(define-libmpg123 mpg123_getparam2
|
||||
(_fun _mpg123_handle _mpg123_param
|
||||
(value : (_ptr io _long ))
|
||||
(fvalue : (_ptr io _double ))
|
||||
-> (r : _MPG123_Result)
|
||||
-> (values r value fvalue)))
|
||||
|
||||
;MPG123_EXPORT int mpg123_param2 ( mpg123_handle * mh,
|
||||
; int type,
|
||||
; long value,
|
||||
; double fvalue
|
||||
; )
|
||||
(define-libmpg123 mpg123_param2
|
||||
(_fun _mpg123_handle _mpg123_param
|
||||
_long _double
|
||||
-> _int))
|
||||
|
||||
|
||||
#|
|
||||
#include <ao/ao.h>
|
||||
#include <mpg123.h>
|
||||
|
||||
#define BITS 8
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
mpg123_handle *mh;
|
||||
unsigned char *buffer;
|
||||
size_t buffer_size;
|
||||
size_t done;
|
||||
int err;
|
||||
|
||||
int driver;
|
||||
ao_device *dev;
|
||||
|
||||
ao_sample_format format;
|
||||
int channels, encoding;
|
||||
long rate;
|
||||
|
||||
if(argc < 2)
|
||||
exit(0);
|
||||
|
||||
/* initializations */
|
||||
ao_initialize();
|
||||
driver = ao_default_driver_id();
|
||||
mpg123_init();
|
||||
mh = mpg123_new(NULL, &err);
|
||||
buffer_size = mpg123_outblock(mh);
|
||||
buffer = (unsigned char*) malloc(buffer_size * sizeof(unsigned char));
|
||||
|
||||
/* open the file and get the decoding format */
|
||||
mpg123_open(mh, argv[1]);
|
||||
mpg123_getformat(mh, &rate, &channels, &encoding);
|
||||
|
||||
/* set the output format and open the output device */
|
||||
format.bits = mpg123_encsize(encoding) * BITS;
|
||||
format.rate = rate;
|
||||
format.channels = channels;
|
||||
format.byte_format = AO_FMT_NATIVE;
|
||||
format.matrix = 0;
|
||||
dev = ao_open_live(driver, &format, NULL);
|
||||
|
||||
/* decode and play */
|
||||
while (mpg123_read(mh, buffer, buffer_size, &done) == MPG123_OK)
|
||||
ao_play(dev, buffer, done);
|
||||
|
||||
/* clean up */
|
||||
free(buffer);
|
||||
ao_close(dev);
|
||||
mpg123_close(mh);
|
||||
mpg123_delete(mh);
|
||||
mpg123_exit();
|
||||
ao_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|#
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Our interface for decoding to racket
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define BITS 8)
|
||||
|
||||
(define (mpg123-ffi-decoder-handler)
|
||||
|
||||
(define mh #f)
|
||||
|
||||
(define buf-size -1)
|
||||
(define buffer #f)
|
||||
|
||||
(define rate -1)
|
||||
(define channels -1)
|
||||
(define sample-bits -1)
|
||||
(define sample-bytes -1)
|
||||
(define pcm-length -1)
|
||||
(define encoding -1)
|
||||
(define mp3-file "")
|
||||
(define current-pcm-pos 0)
|
||||
|
||||
(define (new)
|
||||
(if (eq? mh #f)
|
||||
(let-values ([(h err) (mpg123_new #f)])
|
||||
(when (eq? h #f)
|
||||
(error (format "mpg123_new: ~a" (mpg123_int_strerror err))))
|
||||
(set! mh h)
|
||||
(set! buf-size (mpg123_outblock mh))
|
||||
(set! buffer (malloc buf-size 'atomic-interior ))
|
||||
)
|
||||
(error "mpg123 handle already initialized, delete it first"))
|
||||
#t)
|
||||
|
||||
(define (delete)
|
||||
(if (eq? mh #f)
|
||||
(error "mpg123 has already been deleted")
|
||||
(begin
|
||||
(mpg123_delete mh)
|
||||
(set! mh #f)
|
||||
(set! buf-size -1)
|
||||
(set! buffer #f)
|
||||
))
|
||||
#t)
|
||||
|
||||
(define (info)
|
||||
(info-sound "file : ~a" mp3-file)
|
||||
(info-sound "buf-size : ~a" buf-size)
|
||||
(info-sound "channels : ~a" channels)
|
||||
(info-sound "sample-bits: ~a" sample-bits)
|
||||
(info-sound "rate : ~a" rate)
|
||||
(info-sound "encoding : ~a" encoding)
|
||||
(info-sound "pcm-length : ~a" pcm-length)
|
||||
(info-sound "duration : ~a" (if (= rate -1)
|
||||
0
|
||||
(exact->inexact
|
||||
(/ pcm-length rate))))
|
||||
#t
|
||||
)
|
||||
|
||||
(define (params)
|
||||
(for-each
|
||||
(λ (p)
|
||||
(let-values ([(r v fv) (mpg123_getparam2 mh p 0 0.0)])
|
||||
(info-sound "~a: ~a - ~a - ~a" p r v fv)))
|
||||
'(force-mono mono-left mono-right mono-mix
|
||||
force-stereo force-8bit
|
||||
quiet
|
||||
gapless
|
||||
no-resync seekbuffer fuzzy
|
||||
force-float
|
||||
plain-id3text ignore-streamlength skip-id3v2 ignore-infoframe
|
||||
auto-resample
|
||||
)))
|
||||
|
||||
(define (set-param p val)
|
||||
(mpg123_param2 mh p val (exact->inexact val)))
|
||||
|
||||
(define (do-format)
|
||||
(dbg-sound "do-format called, got an MPG123_NEW_FORMAT message")
|
||||
(let-values ([(fr rate* channels* encoding*) (mpg123_getformat mh)])
|
||||
(unless (eq? fr 'MPG123_OK)
|
||||
(error (format "mpg123_format: ~a" (mpg123_plain_strerror fr))))
|
||||
(set! rate rate*)
|
||||
(set! channels channels*)
|
||||
(set! encoding encoding*)
|
||||
(dbg-sound "mpg123_format: ~a ~a ~a" rate channels encoding)
|
||||
(set! sample-bits (* (mpg123_encsize encoding) BITS))
|
||||
(set! sample-bytes (/ sample-bits 8)))
|
||||
(let ((sr (mpg123_scan mh)))
|
||||
(unless (eq? sr 'MPG123_OK)
|
||||
(error (format "mpg123_scan: ~a" (mpg123_plain_strerror sr))))
|
||||
(set! pcm-length (mpg123_length64 mh)))
|
||||
)
|
||||
|
||||
(define (init file)
|
||||
(let ((r (mpg123_open mh file)))
|
||||
(unless (eq? r 'MPG123_OK)
|
||||
(error (format "mpg123_open: ~a" (mpg123_plain_strerror r))))
|
||||
)
|
||||
(set! mp3-file (format "~a" file))
|
||||
(set! current-pcm-pos 0)
|
||||
#t)
|
||||
|
||||
(define (mp3-format cb)
|
||||
(cb current-pcm-pos rate channels sample-bits sample-bytes pcm-length))
|
||||
|
||||
(define (close)
|
||||
(let ((r (mpg123_close mh)))
|
||||
(unless (eq? r 'MPG123_OK)
|
||||
(error (format "mpg123_close: ~a" (mpg123_plain_strerror r))))
|
||||
(set! channels -1)
|
||||
(set! pcm-length -1)
|
||||
(set! rate -1)
|
||||
(set! sample-bits -1)
|
||||
(set! sample-bytes -1)
|
||||
(set! encoding -1)
|
||||
(set! mp3-file "")
|
||||
#t))
|
||||
|
||||
(define (copy-buffer buf size)
|
||||
(cond
|
||||
((> size 0)
|
||||
(let ((out (make-bytes size)))
|
||||
(memcpy out buf size)
|
||||
out))
|
||||
((= size 0)
|
||||
(make-bytes 0))
|
||||
(else
|
||||
#f)))
|
||||
|
||||
(define (read cb format-cb)
|
||||
(let-values ([(r done) (mpg123_read mh buffer buf-size)])
|
||||
(cond
|
||||
((eq? r 'MPG123_DONE) (cb 'done -1 (copy-buffer buffer done) done))
|
||||
((eq? r 'MPG123_NEW_FORMAT) (do-format)
|
||||
(mp3-format format-cb)
|
||||
(read cb format-cb))
|
||||
((eq? r 'MPG123_OK) (let ((pcm-pos (mpg123_tell64 mh)))
|
||||
(set! current-pcm-pos pcm-pos)
|
||||
(cb 'data pcm-pos (copy-buffer buffer done) done)))
|
||||
(else (error (format "mpg123_read: ~a" (mpg123_plain_strerror r))))
|
||||
)
|
||||
)
|
||||
#t)
|
||||
|
||||
(define (seek pcm-pos)
|
||||
(let ((r (mpg123_seek64 mh pcm-pos 'seek-set)))
|
||||
(unless (>= r 0)
|
||||
(error (format "mpg123_seek64: ~a" (mpg123_int_strerror r))))
|
||||
#t))
|
||||
|
||||
(define (tell)
|
||||
(mpg123_tell64 mh))
|
||||
|
||||
(λ (cmd . args)
|
||||
(cond
|
||||
[(eq? cmd 'new) (new)]
|
||||
[(eq? cmd 'delete) (delete)]
|
||||
[(eq? cmd 'init) (init (car args))]
|
||||
[(eq? cmd 'close) (close)]
|
||||
[(eq? cmd 'format) (mp3-format (car args))]
|
||||
[(eq? cmd 'info) (info)]
|
||||
[(eq? cmd 'read) (read (car args) (cadr args))]
|
||||
[(eq? cmd 'seek) (seek (car args))]
|
||||
[(eq? cmd 'tell) (tell)]
|
||||
[(eq? cmd 'file) mp3-file]
|
||||
[(eq? cmd 'params) (params)]
|
||||
[(eq? cmd 'set-param) (set-param (car args) (cadr args))]
|
||||
[else (error (format "Unknown command: ~a" cmd))]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
); end of module
|
||||
Reference in New Issue
Block a user