;********************************************************************* ; OM-SoX, (c) 2011-2014 Marlon Schumacher (CIRMMT/McGill University) * ; http://sourceforge.net/projects/omsox/ * ; * ; Multichannel Audio Manipulation and Functional Batch Processing. * ; DSP based on SoX - (c) C.Bagwell and Contributors * ; http://sox.sourceforge.net/ * ;********************************************************************* ; ;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. ; ;See file LICENSE for further informations on licensing terms. ; ;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,10 USA. ; ;Authors: M. Schumacher (in-package :om) ; %%%%%%%%%%%%%%% SOX-PROCESS %%%%%%%%%%%%%%%%%%%% ; Main Processing Function ;== method for pathname + string ======= (defmethod! sox-process ((sox-input pathname) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) :icon 08 :initvals '(nil "" "realtime" nil nil nil Off "break") :menuins (list (list 2 *sox-output-options*) (list 3 *sox-file-formats*) (list 4 *sox-samplerates*) (list 5 *sox-bitdephts*) (list 6 '(("On" On) ("Off" Off))) (list 7 '(("break" break) ("repeat" repeat) ("cycle" cycle)))) :indoc '("Audio input to be processed [sound, path, string/pipe, sox-input]" "Sox-effect to be applied to audio input [string]" "Output type (new file, replace file, pipe, or realtime) [string]. Also accepts directory, filename, filepath [path]" "Filetype of produced audio [string]" "Samplerate of produced audio [string]" "Bitdepth of produced audio [number]" "recursive (when 'on' applies processing recursively to audio) [symbol]" "Mode for batch-processing (break, repeat, cycle) [symbol]") :doc "Main audio processing function for OM-SoX. Takes audio provided in and processes it with sox-effects provided in . determines whether output is to be rendered into a) new file, b) replace the input file, c) create a sox-command as a pipe (for further processing), d) play back in realtime through audio device. Alternatively, a filename, directory, or path can be provided which will write an audio file to the given destination. It is also posisble to connect a function/patch in lambda mode, which (if available) will receive the path of as first argument. This can be used to algorithmically name output files (e.g. in batch processes). Optionally, the audio output can be specified, as well as the and (default: same as input). is an experimental option allowing to apply a sox-effect recursively to audio input (e.g. trimming). determines the behaviour when processing lists of sox-inputs and sox-effects that differ in length. " (if (probe-file *sox-path*) (let ((outfile (create-path sox-input output filetype))) (setf str (format nil "~s ~a ~s" (namestring *sox-path*) *sox-options* (namestring sox-input))) (setf str (cond ((equal output "realtime") (sox-samplebits (string+ str " -q ") bitdepth samplerate *sox-audio-device*)) ((equal output "pipe") (sox-samplebits str bitdepth samplerate '-p)) (t (sox-samplebits str bitdepth samplerate outfile)))) (setf str (string+ str sox-effect)) ; optional removal of temp-files (if *delete-inter-file* (let ((outstring (sox-out str sox-input output outfile recursive))) (if (>= *om-version* 6.07) (om-run-process "cleantempfiles" #'sleep&clean 5) (om-run-process "cleantempfiles" sleep&clean 5)) outstring) (sox-out str sox-input output outfile recursive) )) (sox-not-found)) ) ;== method for sound + string ======= (defmethod! sox-process ((sox-input sound) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (let ((gainval (sox-vol-convert (vol sox-input))) (panval (+ (tracknum sox-input) (* 0.01 (pan sox-input))))) (if (equal (tracknum sox-input) 0) (sox-process (sound-path sox-input) (string+ sox-effect " gain " (makestring gainval)) :output output :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode) (sox-process (make-instance 'sox-pan :sound sox-input :gains gainval :panning panval :numchannels nil) sox-effect :output output :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode))) ) ;== method for string + string ======= ;-> allows for arbitrary 'manual' sox-effect or options or pipe inputs... (defmethod! sox-process ((sox-input string) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (if (probe-file *sox-path*) ;catch exception --------- (if (and (pipe-p sox-input) (equal output "pipe") ) (om-message-abort "Pipe output not possible with this type of input.") ; ------------------------ (let ((outfile (create-path nil output filetype))) (setf str (format nil "~s ~a ~s" (namestring *sox-path*) *sox-options* sox-input)) (setf str (cond ((equal output "realtime") (sox-samplebits (string+ str " -q ") bitdepth samplerate *sox-audio-device*)) ((equal output "pipe") (sox-samplebits str bitdepth samplerate '-p)) (t (sox-samplebits str bitdepth samplerate outfile)))) (setf str (string+ str sox-effect)) (if *delete-inter-file* (let ((outstring (sox-out str sox-input output outfile recursive))) (if (>= *om-version* 6.07) (om-run-process "cleantempfiles" #'sleep&clean 5) (om-run-process "cleantempfiles" sleep&clean 5)) outstring) (sox-out str sox-input output outfile recursive) ))) (sox-not-found)) ) ; %%%%%%%% METHODS FOR SOX-INPUT CLASSES %%%%%%%%%%%% ; === sox-merge ============= (defmethod! sox-process ((sox-input sox-merge) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (if (probe-file *sox-path*) (progn ;(print (sound sox-input)) (let* ((sound (if (> (length (gains sox-input)) (length (list! (sound sox-input)))) (repeat-n (first (list! (sound sox-input))) (length (gains sox-input))) (sound sox-input)))) (when (and (find-if 'stringp sound) (equal output "pipe")) (om-message-abort "Pipe output not possible with this type of input.")) (let ((outfile (create-path nil output filetype))) ;(create-path (first (soundfiles sox-input)) output filetype) (let* ((filenames (loop for soundfile in sound collect (namestring soundfile)))) (setf str (format nil "~s ~a -M " (namestring *sox-path*) *sox-options* )) (if (gains sox-input) (loop for filename in filenames do for gain in (db->lin (list! (gains sox-input))) do (setf str (string+ str (format nil " -v~d ~s " gain filename)))) (loop for filename in filenames do (setf str (string+ str (format nil " ~s" filename))))) (setf str (cond ((equal output "realtime") (sox-samplebits (string+ str " -q ") bitdepth samplerate *sox-audio-device*)) ((equal output "pipe") (sox-samplebits str bitdepth samplerate "-p")) (t (sox-samplebits str bitdepth samplerate outfile)))) (setf str (string+ str sox-effect)) (sox-out str sox-input output outfile recursive))))) (sox-not-found)) ) ; === sox-hoaencode ============= (defmethod! sox-process ((sox-input sox-hoaencode) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) ; would be more consistent with OO programming to have a function sox-hoaencode->sox-merge ; (consider how to deal with multiple sounds to be hoaencoded and mixed later on... sox-mix might be better done in an explicit way rather than via the class directly. ; in that case a 3DC would have to be used by using points (point-pairs) in a loop (if (probe-file *sox-path*) (progn (let ((sound (sound sox-input))) (when (and (stringp sound) (equal output "pipe")) (om-message-abort "Pipe output not possible with this type of input.")) (let ((filename (namestring sound)) (outfile (create-path nil output filetype))) (setf str (format nil " ~s ~a" (namestring *sox-path*) *sox-options*)) (if (= (order sox-input) 0) ; case: order = 0 (setf str (string+ str (format nil " ~s" filename))) ; case: order > 0 (progn ; here it would be more redundant to call sox-merge with the given params (setf str (string+ str " -M")) (loop for gain in (sox-hoaencode-gains-up-to-order (order sox-input) (azimuth sox-input) (elevation sox-input)) do (setf str (string+ str (format nil " -v~d ~s" gain filename)))) ) ) ; ) (setf str (cond ((equal output "realtime") (sox-samplebits (string+ str " -q ") bitdepth samplerate *sox-audio-device*)) ((equal output "pipe") (sox-samplebits str bitdepth samplerate "-p")) (t (sox-samplebits str bitdepth samplerate outfile)) ) ) (setf str (string+ str sox-effect)) (print str) (sox-out str sox-input output outfile recursive) ;optional removal of temp file ; (add-tmp-file outfile_tmp) ; (when *delete-inter-file* (clean-tmp-files)) ) ) ) (sox-not-found) ) ) ; === sox-mix ============= (defmethod! sox-process ((sox-input sox-mix) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (if (probe-file *sox-path*) (progn (when (and (find-if 'stringp (sound sox-input)) (equal output "pipe")) (om-message-abort "Pipe output not possible with this type of input.")) (let ((outfile (create-path nil output filetype))) ;(create-path (first (soundfiles sox-input)) output filetype) (let* ((filenames (loop for soundfile in (sound sox-input) collect ;I guess this throws the error when using pipes as inputs (namestring soundfile)))) (setf str (format nil "~s ~a -m " (namestring *sox-path*) *sox-options*)) ;potentially not needed... ;(if (1/n sox-input) ; (loop for filename in filenames do ; for gain in (om/ (db->lin (gains sox-input)) (length (gains sox-input))) do ;(db->lin (list! (gains sox-input))) -> but it's always going to be a list, no? ; (setf str (string+ str (format nil " -v~d ~s " gain filename )))) ; is it not scaling when volumes are given? try out! (loop for filename in filenames do for gain in (db->lin (gains sox-input)) do ;(db->lin (list! (gains sox-input))) -> but it's always going to be a list, no? (setf str (string+ str (format nil " -v~d ~s " gain filename )))) ;) (setf str (cond ((equal output "realtime") (sox-samplebits (string+ str " -q ") bitdepth samplerate *sox-audio-device*)) ((equal output "pipe") (sox-samplebits str bitdepth samplerate "-p")) ; "-p is an alias for '-t sox -' " and it's better but I can't use as I need to provide the sox path again... (t (sox-samplebits str bitdepth samplerate outfile)))) (setf str (string+ str sox-effect)) (sox-out str sox-input output outfile recursive)))) (sox-not-found)) ) ; === sox-multiply ============= (defmethod! sox-process ((sox-input sox-multiply) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (if (probe-file *sox-path*) (progn (when (and (find-if 'stringp (sound sox-input)) (equal output "pipe")) (om-message-abort "Pipe output not possible with this type of input.")) (let ((outfile (create-path nil output filetype))) ;(create-path (first (soundfiles sox-input)) output filetype) (let* ((filenames (loop for soundfile in (sound sox-input) collect ;I guess this throws the error when using pipes as inputs (namestring soundfile)))) (setf str (format nil "~s ~a -T " (namestring *sox-path*) *sox-options*)) (loop for filename in filenames do for gain in (db->lin (gains sox-input)) do (setf str (string+ str (format nil " -v~d ~s " gain filename )))) ; note that "-v" suppresses sox's in-built clipping protection ;) (setf str (cond ((equal output "realtime") (sox-samplebits (string+ str " -q ") bitdepth samplerate *sox-audio-device*)) ((equal output "pipe") (sox-samplebits str bitdepth samplerate "-p")) (t (sox-samplebits str bitdepth samplerate outfile)))) (setf str (string+ str sox-effect)) (sox-out str sox-input output outfile recursive)))) (sox-not-found)) ) ; === sox-concatenate ============= (defmethod! sox-process ((sox-input sox-concatenate) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (if (probe-file *sox-path*) (progn (when (and (find-if 'stringp (sound sox-input)) (equal output "pipe")) (om-message-abort "Pipe output not possible with this type of input.")) (let ((outfile (create-path nil output filetype))) ;(create-path (first (soundfiles sox-input)) output filetype) (let* ((filenames (loop for soundfile in (sound sox-input) collect (namestring soundfile)))) (setf str (format nil "~s ~a " (namestring *sox-path*) *sox-options*)) (if (gains sox-input) (loop for filename in filenames do for gain in (db->lin (list! (gains sox-input))) do (setf str (string+ str (format nil " -v~d ~s " gain filename )))) ;I think this case never happens (loop for filename in filenames do (setf str (string+ str (format nil " ~s" filename))))) (setf str (cond ((equal output "realtime") (sox-samplebits (string+ str " -q ") bitdepth samplerate *sox-audio-device*)) ((equal output "pipe") (sox-samplebits str bitdepth samplerate "-p")) (t (sox-samplebits str bitdepth samplerate outfile)))) (setf str (string+ str sox-effect)) (sox-out str sox-input output outfile recursive)))) (sox-not-found)) ) ; === sox-splice ============ (defmethod! sox-process ((sox-input sox-splice) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (if (probe-file *sox-path*) (progn (when (and (find-if 'stringp (sound sox-input)) (equal output "pipe")) (om-message-abort "Pipe output not possible with this type of input.")) (let ((outfile (create-path nil output filetype))) (let* ((mysoundfiles (sound sox-input)) (filenames (loop for soundfile in mysoundfiles collect (namestring soundfile))) (first-dur (sox-sound-duration (car (sound sox-input)))) (begins (list! (splice-begin sox-input))) (ends (list! (splice-end sox-input))) (tols (list! (tolerance sox-input)))) (sox-print (format nil "begins: ~a" begins)) (sox-print (format nil "ends: ~a" ends)) (sox-print (format nil "tols: ~a" tols)) (setf str (format nil "~s ~a " (namestring *sox-path*) *sox-options*)) (loop for filename in filenames do for gain in (db->lin (list! (gains sox-input))) do (setf str (string+ str (format nil " -v~d ~s " gain filename )))) (setf str (cond ((equal output "realtime") (sox-samplebits (string+ str " -q ") bitdepth samplerate *sox-audio-device*)) ((equal output "pipe") (sox-samplebits str bitdepth samplerate "-p")) (t (sox-samplebits str bitdepth samplerate outfile)))) (setf str (cond ((eql (fade-type sox-input) 'linear) (string+ str (format nil " splice -t " ))) ((eql (fade-type sox-input) 'half-cosine) (string+ str (format nil " splice -h " ))) ((eql (fade-type sox-input) 'quarter-cosine) (string+ str (format nil " splice -q " ))) (t (string+ str (format nil " splice " ))))) ;dbl-check the sum-calculation. Something's fishy! (loop for mysound in (sound sox-input) for end in ends counting end into ordinal summing (or (sox-sound-duration mysound) 0) into dur-sum do (progn (sox-print ordinal) (let ((i (- ordinal 1)) (current-sum (- dur-sum (or first-dur 0)))) (sox-print (format nil "begins: ~d" (nth i begins))) (sox-print (format nil "ends: ~d" (nth i ends))) (sox-print (format nil "current-sum: ~d" current-sum)) (cond ((and (nth i begins) (nth i tols)) (progn (sox-print "begin+tol") (setf str (string+ str (format nil "~d,~d,~d " (+ current-sum (nth i ends)) (* 0.5 (- (nth i ends) (nth i begins))) (nth i tols)))))) ((nth i begins) (progn (print "begin") (setf str (string+ str (format nil "~d,~d " (+ current-sum (nth i ends)) (* 0.5 (- (nth i ends) (nth i begins)))))))) (t (progn (print "end") (setf str (string+ str (format nil "~d " (+ current-sum (nth i ends)))))))) ))) (setf str (sox-commands sox-effect str)) (sox-out str sox-input output outfile recursive) ))) (sox-not-found)) ) ; === sox-remix ============= (defmethod! sox-process ((sox-input sox-remix) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) ;(print (first (channels sox-input))) (if (probe-file *sox-path*) (progn (when (and (stringp (sound sox-input)) (equal output "pipe")) (om-message-abort "Pipe output not possible with this type of input.")) (let* ((inpath (sound sox-input)) (outfile (create-path inpath output filetype)) ;(create-path nil output filetype) (channel-matrix (list! (channel-matrix sox-input)))) ; is this still needed? (setf str (format nil "~s ~a ~s" (namestring *sox-path*) *sox-options* (namestring inpath))) ; (print (channels sox-input)) ; (print (gains sox-input)) (when bitdepth (setf str (string+ str (format nil " -b ~d" bitdepth)))) ;could I not use sox-samplebits here? (setf str (string+ str (format nil " ~s remix ~a" (cond ((equal output "realtime") *sox-audio-device*) ;should add a quiet mode here... ((equal output "pipe") "-p") (t (namestring outfile))) (sox-remixconc-no-norm (gain-matrix sox-input) (channel-matrix sox-input)) ))) (when samplerate (setf str (string+ str (format nil " rate ~d " samplerate)))) (setf str (string+ str sox-effect)) (sox-out str inpath output outfile recursive))) (sox-not-found)) ) ; === sox-pan ==================== (defmethod! sox-process ((sox-input sox-pan) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) ;(print (first (channels sox-input))) (sox-process (sox-pan->sox-remix (sound sox-input) (car (list! (gains sox-input))) (car (list! (panning sox-input))) (numchannels sox-input)) sox-effect :output output :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode)) ; === sox-mix-console ============= ; Notes on polymorphism ; I could make this sox-mix-console (non-consistent) a method where a list of effects will be applied to each sound in the mix-console ; OR: keep this as an extra function for the player ; I can't use pipe-input to the mix-console as it makes sox-remix instances with pipe-outputs ->is a pipe in a pipe not possible? (defmethod! sox-process ((sox-input sox-mix-console) (sox-effect t) &key output filetype samplerate bitdepth recursive batch-mode) (if (probe-file *sox-path*) (progn ;(print "sox-process: sox-mix-console") (when (and (stringp (sound sox-input)) (equal output "pipe")) (om-message-abort "Pipe output not possible with this type of input.")) (let* ((inpath (sound sox-input)) (outfile (create-path inpath output filetype)) ;(create-path nil output filetype) ; Filetype MUST NOT be pipe (it can be only a sound) (list-of-pans (loop for path in (list! inpath) for gain in (gains sox-input) for pan in (panning sox-input) collect (make-instance 'sox-pan :sound path :gains gain :panning pan))) (list-of-pipes (loop for sox-pan in list-of-pans for i from 0 to (length list-of-pans) collect (sox-process sox-pan (or (nth i (list! sox-effect)) "") ;note that in this special case a list of effects is applied to each in-sound :output "pipe" :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode))) ) (if (> (length list-of-pipes) 1) (sox-process (make-instance 'sox-mix :sound list-of-pipes) "" :output output :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode ) (sox-process list-of-pipes "" :output output :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode )) )) (sox-not-found) )) ; === sox-split ============= ; special method with (sox-effect t) only for sox-split (returns a sequence of sox-remixes) (defmethod! sox-process ((sox-input sox-split) (sox-effect t) &key output filetype samplerate bitdepth recursive batch-mode) (if (probe-file *sox-path*) (progn (cond ((equal output "replace file") (om-message-abort "Replace output not possible with sox-split.")) ((and (equal output "pipe") (stringp (sound sox-input))) (om-message-abort "Pipe output not possible with this type of input"))) (let* ((thesoundfile (sound sox-input)) (list-of-remixes (loop for channel in (channels sox-input) for gain in (gains sox-input) collect (make-instance 'sox-remix :sound thesoundfile :gain-matrix (list gain) :channel-matrix (list (list channel))))) ;here the 'realtime' and 'pipe' ?? (list-of-outpaths (loop for channel in (channels sox-input) collect (format nil "~a_omsox-ch~d" (pathname-name thesoundfile) channel)) )) (sox-process list-of-remixes sox-effect :output (or output list-of-outpaths) :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode))) (sox-not-found)) ) ; === sox-record ============= (defmethod! sox-process ((sox-input sox-record) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (if (probe-file *sox-path*) (let ((outfile (create-path nil output filetype))) (setf str (format nil "~s ~a ~s" (namestring *sox-path*) *sox-options* *sox-audio-device*)) ;perhaps sox-recording vs playback-device? (setf str (cond ((equal output "realtime") (sox-samplebits (string+ str " -q ") bitdepth samplerate *sox-audio-device*)) ((equal output "pipe") (sox-samplebits (string+ str " -q ") bitdepth samplerate "-p")) (t (sox-samplebits (string+ str " -q ") bitdepth samplerate outfile)))) (setf str (string+ str (format nil " trim 0 ~d " (duration sox-input)))) (cond ((and (channels sox-input) (gains sox-input)) (let ((newstr (format nil " remix" ))) (loop for channel in (channels sox-input) for gain in (gains sox-input) do (setf newstr (string+ newstr (format nil " ~av~d " channel (db->lin gain))))) (setf str (string+ str newstr)))) ((gains sox-input) (let ((newstr (format nil " remix" ))) (loop for item from 1 to (length (gains sox-input)) for gain in (gains sox-input) do (setf newstr (string+ newstr (format nil " ~av~d " item (db->lin gain))))) (setf str (string+ str newstr)))) ((channels sox-input) (let ((newstr (format nil " remix" ))) (loop for channel in (channels sox-input) do (setf newstr (string+ newstr (format nil " ~a" channel)))) (setf str (string+ str newstr)))) ) (setf str (string+ str sox-effect)) (sox-out str sox-input output outfile recursive)) (sox-not-found)) ) ; === sox synth ========= #| (defmethod! sox-process ((sox-input sox-synth) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (if (probe-file *sox-path*) (let ((outfile (create-path nil output filetype))) (setf str (format nil "~s ~a -n" (namestring *sox-path*) *sox-options*)) (setf str (cond ((equal output "realtime") (sox-samplebits (string+ str " -q ") bitdepth samplerate *sox-audio-device*)) ((equal output "pipe") (sox-samplebits str bitdepth samplerate '-p)) (t (sox-samplebits str bitdepth samplerate outfile)))) (setf str (string+ str " synth" (sox-synth-format sox-input))) (setf str (string+ str sox-effect)) (sox-out str sox-input output outfile recursive)) (sox-not-found)) ) |# ; %%%%%%%%%%%% LIST METHODS %%%%%%%%%%%%%%%%%%%%%% ; for string + list + list/string (defmethod! sox-process ((sox-input t) (sox-effect list) &key output filetype samplerate bitdepth recursive batch-mode) (if (and (listp output) (first output)) (mapcar (lambda (thesox-effect thepath) (sox-process sox-input thesox-effect :output thepath :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode)) sox-effect output) (mapcar (lambda (thesox-effect) (sox-process sox-input thesox-effect :output output :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode)) sox-effect))) ; these functions below can be grouped together into multiple if/when statements for the different types of 'output' ;-------------------------------------------------------------------------------------------------------------------- ; for list + string + string (defmethod! sox-process ((sox-input list) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (mapcar (lambda (file) (sox-process file sox-effect :output output :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode)) sox-input)) ; #### NEED TO MAKE AN EXAMPLE FOR THIS CASE // ALSO, THE LIST LIST FUNCTION method seems to be missing.. PROBABLY FOR AUTO_NAMING FILES (batch processing) ; for list + string + function (defmethod! sox-process ((sox-input list) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (if (functionp output) ; these 2 cases seem to be identical (mapcar (lambda (file) (sox-process file sox-effect :output output :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode)) sox-input) (mapcar (lambda (file) (sox-process file sox-effect :output output :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode)) sox-input))) ; for list + string + list (defmethod! sox-process ((sox-input list) (sox-effect string) &key output filetype samplerate bitdepth recursive batch-mode) (if (and (listp output) (first output)) (mapcar (lambda (file thepath) (sox-process file sox-effect :output thepath :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode)) sox-input output) (mapcar (lambda (file) (sox-process file sox-effect :output output :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode)) sox-input))) ; --------------------------------------------------------------------------------------------------------------------- ; for list + list + string/list (defmethod! sox-process ((sox-input list) (sox-effect list) &key output filetype samplerate bitdepth recursive batch-mode) (let ( (numsounds (length sox-input)) (numsox-effect (length sox-effect))) (when (> numsounds numsox-effect) (progn (when (equal batch-mode 'cycle) (setf sox-effect (flat (group-list sox-effect (list numsounds) 'circular)))) (when (equal batch-mode 'repeat) (setf sox-effect (flat (x-append sox-effect (repeat-n (last sox-effect) (- numsounds numsox-effect)))))))) (if (consp output) (mapcar (lambda (file thesox-effect thepaths) (sox-process file thesox-effect :output thepaths :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode)) sox-input sox-effect output) (mapcar (lambda (file thesox-effect) (sox-process file thesox-effect :output output :filetype filetype :samplerate samplerate :bitdepth bitdepth :recursive recursive :batch-mode batch-mode)) sox-input sox-effect)))) ; for anything else beep ------------------ (defmethod! sox-process ((sox-input t) (sox-effect t) &key output filetype samplerate bitdepth recursive batch-mode) (om-beep-msg (format nil "!!! Wrong input type or command for sox-process: ~A with ~A" sox-input sox-effect)))