Work-in-progress repo for ambisonics extensions for OM-SoX
Marlon Schumacher
24.02.25 197ce0f724aa567c7401f63dc889e7861ed8c0aa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
;*********************************************************************
; OM-SoX, (c) 2011-2015 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)
 
(defclass* sound (simple-score-element internalsound) 
  ((tracknum :accessor tracknum :initarg :tracknum :initform 0 :documentation "a track index for multichannel mixing")
   (markers :accessor markers :initarg :markers :initform nil :documentation "a list of markers (s)")
   (vol :accessor vol :initform 1.0)  ;NB the default for vol is set to 0 for *all players* in OM when OM-Versions > 6.07
   (pan :accessor pan :initform 0))  
   (:icon 287)
   (:documentation "Sound file object.
 
A sound is initialized with a pathname corresponding to an audio file on the disk.
Connect a pathname to the first input (<self>) to initialize the instance. 
If it is unlocked and unconnected, evaluating the box will open a file chooser dialog and allow the selection of a sound file to load.
 
The other inputs/outputs correspond to :
- <tracknum> = a track number on which the sound will be dispatch at playback. Tracknum can also be changed from the sound editor.
- <markers> = a list of markers (time in seconds). The markers can also be added/moved/removed from the sound editor.
 
NOTE: These inputs can be connected and will be evaluated even if something is connected to he <self> input of the box.
 
Press 'space' to play/stop the sound file.
"))
 
 
; set sox as default sound player 
(defmethod get-default-score-params ((self sound))
  (pairlis '(approx fontsize staff cmnpref deltapict outport inport player
             zoom notechancolor? grillestep mode winsize winpos score-mode obj-mode show-stems scale) 
           (list *global-midi-approx* *music-fontsize* *default-satff* (make-instance 'edition-values) (om-make-point 0 0) 
                 nil *InMidiPort* :soxplayer
                 1 nil 1000 0 (om-make-point 370 280) (om-make-point 400 20) 0 1 t nil)))
 
(defmethod save-exepcion ((self sound)) 
  (and (om-sound-file-name self)
        (register-resource :sound (om-sound-file-name self))
        `(let ((thesound (load-sound ,(om-save-pathname-relative (om-sound-file-name self))
                                     ,(tracknum self)
                                     ,(vol self)
                                     ,(pan self)
                                     )))
           (when thesound
             (setf (markers thesound) ',(markers self)))
           thesound)))
 
 
(defun load-sound (name &optional track vol pan)
  (let ((snd (om-load-if name 'load-sound-file)))
    (unless snd (setf snd (make-instance 'sound :filename name)))
    (when (and snd track) (setf (tracknum snd) track))
    (when (and snd vol) (setf (vol snd) vol))
    (when (and snd pan) (setf (pan snd) pan))
    snd))
 
(defmethod audio-player-track-range ((player (eql :soxplayer))) '(0 32))
(defmethod audio-player-vol-range ((player (eql :soxplayer))) '(0 4)) ; up to +12 db (headroom)
 
(defmethod copy-container ((self sound) &optional (pere ()))
  (let ((snd (if (om-sound-file-name self) 
                 (let ((copy (load-sound-file (om-sound-file-name self)))
                       (slots  (class-instance-slots (find-class 'simple-container))))
                   (setf (slot-value copy 'parent) pere)
                   (loop for slot in slots
                       when (not (eq (slot-definition-name slot) 'parent))
                       do (setf (slot-value  copy  (slot-definition-name slot))
                            (copy-container (slot-value self  (slot-definition-name slot)) copy)))
                   copy)
               (make-instance 'sound))))
    (setf (tracknum snd) (tracknum self))
    (setf (markers snd) (markers self))
    (setf (pan snd) (pan self))
    (setf (vol snd) (vol self))
    (setf (pict-spectre snd) (pict-spectre self))
    (when (< *om-version* 6.08) (setf (pict-spectre? snd) (pict-spectre? self))) 
    snd))
 
; this is kind of a hack to copy the tracknum when connecting a sound obj to another sound obj
; while still being able to 'override' this by providing a tracknum to the <tracknum> inlet
; NB: the value '0' cannot be provided through the tracknum inlet when self is connected to a sound, i.e. it will take the tracknum of the 'pere' sound obj
(defmethod cons-new-object ((self sound) args objs)
  (let ((rep (call-next-method)))
    (nth 1 args)
    (when rep
      (setf (tracknum rep) (if (and (integerp (nth 1 args)) (> (nth 1 args) 0)) (nth 1 args) (tracknum rep)))
      (when (consp (nth 2 args)) (setf (markers rep) (nth 2 args))))
    rep))
 
 
; Support loading audio formats other than .aif or .wav
 
; the variable au::*additional-audio-formats* is not bound in OM6.11 anymore, thus replacing here with *additional-audio-formats* from waveform.lisp (now in preferences.lisp)
#|
(defparameter *sox-additional-audio-formats* '((:sox-formats "flac" "3gp" "caf" "au" "raw" "f32" "f64" "s8" "s16" "s24" "s32" "u8" "u16" "u24" "u32" "ul" "al" "lu" "la" "cdda" "cdr" "f4" "f8" "s1" "s2" "s3" "s4" "u1" "u2" "u3" "u4" "sb" "sw" "sl" "ub" "uw" "8svx" "aiffc" "aifc" "amb" "amr-nb" "amr-w" "au" "snd" "avr" "cvsd" "cvs" "cvu" "dat" "dvms" "vms" "fap" "paf" "ffmpeg" "flac" "fssd" "gsm" "hcom" "htk" "ircam" "ima" "lpc" "lpc10" "mat" "mat4" "mat5" "m3u" "mp3" "mp2" "mp4" "m4a" "maud" "nist" "sph" "ogg" "vorbis" "prc" "pvf" "sd2" "sds" "sf" "sph" "nist" "smp" "sndr" "sndt" "sndfile" "sndio" "sndr" "sndt" "sou" "txw" "vms" "dvms" "voc" "w64" "wav" "waveaudio" "wavpcm" "wv" "wve" "xa" "xi")))
|#
 
;; study this 
(loop for item in (cdr (find :sox-formats *additional-audio-formats* :key 'car)) do
      (eval 
       `(defmethod get-obj-from-file ((type (eql ',(interne item))) filename)
          (load-sound-file filename))
       ))
 
; ADD MORE METHODS HERE (for all the supported filetypes)
 
(defmethod draw-obj-in-rect ((self sound) x x1 y y1 edparams view) 
  (let ((picture (if (>= *om-version* 6.08)
                     (if (and (pict-spectre self) (get-param edparams :show-spectrum))
                         (thepict (pict-spectre self))
                       (sound-get-pict self))
                   (pic-to-draw self)))
        )
    (om-with-focused-view view 
      (if picture
          (let ((dur (/ (om-sound-n-samples self) (om-sound-sample-rate self)))
                (pos x) (w (- x1 x)) (h (h view)))
            (om-with-fg-color view *om-dark-gray-color*
              (if  (< *om-version* 6.09)
                  (om-draw-picture view picture (om-make-point x y) (om-make-point (- x1 x) (- y1 y))))
              (om-draw-picture view picture :pos (om-make-point x y) :size (om-make-point (- x1 x) (- y1 y))))
            (om-with-fg-color view *om-steel-blue-color*
              (om-with-line '(2 2)
                (loop for item in (markers self) do
                      (setf pos (+ x (round (* w item) dur)))
                      (om-draw-line pos y pos y1)))))
        )
      )))
 
 
 
; make-sound method =============
 
(defmethod! make-sound ((file pathname) (tracknum number) (vol number) (pan number) (player symbol))
            (let ((mysound (make-instance 'sound :filename file)))
              (setf (tracknum mysound) tracknum)
              (setf (vol mysound) vol)
              (setf (pan mysound) pan)
              (setf (extent mysound) nil)
            mysound))